zero-agent 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.
- agentz/agent/base.py +262 -0
- agentz/artifacts/__init__.py +5 -0
- agentz/artifacts/artifact_writer.py +538 -0
- agentz/artifacts/reporter.py +235 -0
- agentz/artifacts/terminal_writer.py +100 -0
- agentz/context/__init__.py +6 -0
- agentz/context/context.py +91 -0
- agentz/context/conversation.py +205 -0
- agentz/context/data_store.py +208 -0
- agentz/llm/llm_setup.py +156 -0
- agentz/mcp/manager.py +142 -0
- agentz/mcp/patches.py +88 -0
- agentz/mcp/servers/chrome_devtools/server.py +14 -0
- agentz/profiles/base.py +108 -0
- agentz/profiles/data/data_analysis.py +38 -0
- agentz/profiles/data/data_loader.py +35 -0
- agentz/profiles/data/evaluation.py +43 -0
- agentz/profiles/data/model_training.py +47 -0
- agentz/profiles/data/preprocessing.py +47 -0
- agentz/profiles/data/visualization.py +47 -0
- agentz/profiles/manager/evaluate.py +51 -0
- agentz/profiles/manager/memory.py +62 -0
- agentz/profiles/manager/observe.py +48 -0
- agentz/profiles/manager/routing.py +66 -0
- agentz/profiles/manager/writer.py +51 -0
- agentz/profiles/mcp/browser.py +21 -0
- agentz/profiles/mcp/chrome.py +21 -0
- agentz/profiles/mcp/notion.py +21 -0
- agentz/runner/__init__.py +74 -0
- agentz/runner/base.py +28 -0
- agentz/runner/executor.py +320 -0
- agentz/runner/hooks.py +110 -0
- agentz/runner/iteration.py +142 -0
- agentz/runner/patterns.py +215 -0
- agentz/runner/tracker.py +188 -0
- agentz/runner/utils.py +45 -0
- agentz/runner/workflow.py +250 -0
- agentz/tools/__init__.py +20 -0
- agentz/tools/data_tools/__init__.py +17 -0
- agentz/tools/data_tools/data_analysis.py +152 -0
- agentz/tools/data_tools/data_loading.py +92 -0
- agentz/tools/data_tools/evaluation.py +175 -0
- agentz/tools/data_tools/helpers.py +120 -0
- agentz/tools/data_tools/model_training.py +192 -0
- agentz/tools/data_tools/preprocessing.py +229 -0
- agentz/tools/data_tools/visualization.py +281 -0
- agentz/utils/__init__.py +69 -0
- agentz/utils/config.py +708 -0
- agentz/utils/helpers.py +10 -0
- agentz/utils/parsers.py +142 -0
- agentz/utils/printer.py +539 -0
- pipelines/base.py +972 -0
- pipelines/data_scientist.py +97 -0
- pipelines/data_scientist_memory.py +151 -0
- pipelines/experience_learner.py +0 -0
- pipelines/prompt_generator.py +0 -0
- pipelines/simple.py +78 -0
- pipelines/simple_browser.py +145 -0
- pipelines/simple_chrome.py +75 -0
- pipelines/simple_notion.py +103 -0
- pipelines/tool_builder.py +0 -0
- zero_agent-0.1.0.dist-info/METADATA +269 -0
- zero_agent-0.1.0.dist-info/RECORD +66 -0
- zero_agent-0.1.0.dist-info/WHEEL +5 -0
- zero_agent-0.1.0.dist-info/licenses/LICENSE +21 -0
- zero_agent-0.1.0.dist-info/top_level.txt +2 -0
agentz/agent/base.py
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import json
|
4
|
+
from typing import Any, Callable, Optional
|
5
|
+
|
6
|
+
from pydantic import BaseModel
|
7
|
+
|
8
|
+
from agents import Agent, RunResult
|
9
|
+
from agents.run_context import TContext
|
10
|
+
|
11
|
+
PromptBuilder = Callable[[Any, Any, "ContextAgent"], str]
|
12
|
+
|
13
|
+
|
14
|
+
class ContextAgent(Agent[TContext]):
|
15
|
+
"""Capability-centric wrapper that binds LLM + tools + typed IO contract."""
|
16
|
+
|
17
|
+
def __init__(
|
18
|
+
self,
|
19
|
+
*args: Any,
|
20
|
+
input_model: type[BaseModel] | None = None,
|
21
|
+
output_model: type[BaseModel] | None = None,
|
22
|
+
prompt_builder: PromptBuilder | None = None,
|
23
|
+
default_span_type: str = "agent",
|
24
|
+
output_parser: Optional[Callable[[str], Any]] = None,
|
25
|
+
**kwargs: Any,
|
26
|
+
) -> None:
|
27
|
+
if output_model and kwargs.get("output_type"):
|
28
|
+
raise ValueError("Use either output_model or output_type, not both.")
|
29
|
+
if output_model is not None:
|
30
|
+
kwargs["output_type"] = output_model
|
31
|
+
|
32
|
+
super().__init__(*args, **kwargs)
|
33
|
+
|
34
|
+
self.input_model = input_model
|
35
|
+
self.output_model = self._coerce_output_model(output_model or getattr(self, "output_type", None))
|
36
|
+
self.prompt_builder = prompt_builder
|
37
|
+
self.default_span_type = default_span_type
|
38
|
+
self.output_parser = output_parser
|
39
|
+
self._pipeline = None # Optional pipeline reference for context-aware execution
|
40
|
+
self._role = None # Optional role identifier for automatic iteration tracking
|
41
|
+
|
42
|
+
@classmethod
|
43
|
+
def from_profile(cls, pipeline: Any, role: str, llm: str) -> "ContextAgent":
|
44
|
+
"""Create a ContextAgent from a pipeline context and role.
|
45
|
+
|
46
|
+
Automatically looks up the profile from pipeline.context.profiles[role],
|
47
|
+
derives agent name, and binds the agent to the pipeline with the role.
|
48
|
+
|
49
|
+
Args:
|
50
|
+
pipeline: Pipeline instance (must have context.profiles attribute)
|
51
|
+
role: Role name that maps to a profile key (e.g., "observe", "evaluate")
|
52
|
+
llm: LLM model name (e.g., "gpt-4", "claude-3-5-sonnet")
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
ContextAgent instance configured from the profile and bound to pipeline
|
56
|
+
|
57
|
+
Example:
|
58
|
+
agent = ContextAgent.from_profile(self, "observe", "gpt-4")
|
59
|
+
# Looks up profiles["observe"], creates agent, and binds it to pipeline
|
60
|
+
"""
|
61
|
+
# Look up profile from pipeline's context
|
62
|
+
profile = pipeline.context.profiles[role]
|
63
|
+
|
64
|
+
# Auto-derive name from role
|
65
|
+
agent_name = role + "_agent" if role != "agent" else "agent"
|
66
|
+
|
67
|
+
# Get tools, default to empty list if None
|
68
|
+
# Note: Tools in profiles are currently string names, not resolved objects
|
69
|
+
# This causes errors in the agents library which expects tool objects
|
70
|
+
# For now, pass empty list to avoid runtime errors
|
71
|
+
# TODO: Implement tool resolution to make tools actually work
|
72
|
+
tools = []
|
73
|
+
|
74
|
+
agent = cls(
|
75
|
+
name=agent_name,
|
76
|
+
instructions=profile.instructions,
|
77
|
+
output_model=getattr(profile, "output_schema", None),
|
78
|
+
input_model=getattr(profile, "input_schema", None),
|
79
|
+
tools=tools,
|
80
|
+
model=llm,
|
81
|
+
)
|
82
|
+
|
83
|
+
# Bind agent to pipeline with role
|
84
|
+
agent._pipeline = pipeline
|
85
|
+
agent._role = role
|
86
|
+
|
87
|
+
return agent
|
88
|
+
|
89
|
+
@staticmethod
|
90
|
+
def _coerce_output_model(candidate: Any) -> type[BaseModel] | None:
|
91
|
+
if isinstance(candidate, type) and issubclass(candidate, BaseModel):
|
92
|
+
return candidate
|
93
|
+
return None
|
94
|
+
|
95
|
+
def _coerce_input(self, payload: Any, strict: bool = True) -> Any:
|
96
|
+
if self.input_model is None or payload is None:
|
97
|
+
return payload
|
98
|
+
if isinstance(payload, self.input_model):
|
99
|
+
return payload
|
100
|
+
if isinstance(payload, BaseModel):
|
101
|
+
return self.input_model.model_validate(payload.model_dump())
|
102
|
+
if isinstance(payload, dict):
|
103
|
+
return self.input_model.model_validate(payload)
|
104
|
+
|
105
|
+
# If strict mode is disabled, allow passthrough
|
106
|
+
if not strict:
|
107
|
+
return payload
|
108
|
+
|
109
|
+
msg = f"{self.name} expects input compatible with {self.input_model.__name__}"
|
110
|
+
raise TypeError(msg)
|
111
|
+
|
112
|
+
@staticmethod
|
113
|
+
def _to_prompt_payload(payload: Any) -> dict[str, Any]:
|
114
|
+
if payload is None:
|
115
|
+
return {}
|
116
|
+
if isinstance(payload, BaseModel):
|
117
|
+
return payload.model_dump()
|
118
|
+
if isinstance(payload, dict):
|
119
|
+
return payload
|
120
|
+
return {"input": payload}
|
121
|
+
|
122
|
+
def build_prompt(
|
123
|
+
self,
|
124
|
+
payload: Any = None,
|
125
|
+
*,
|
126
|
+
context: Any = None,
|
127
|
+
template: Optional[str] = None,
|
128
|
+
) -> str:
|
129
|
+
validated = self._coerce_input(payload)
|
130
|
+
|
131
|
+
if self.prompt_builder:
|
132
|
+
return self.prompt_builder(validated, context, self)
|
133
|
+
|
134
|
+
if context is not None and template:
|
135
|
+
builder = getattr(context, "build_prompt", None)
|
136
|
+
if builder is None:
|
137
|
+
raise AttributeError("Context object must expose build_prompt(...)")
|
138
|
+
prompt_data = self._to_prompt_payload(validated)
|
139
|
+
return builder(agent=self, template_name=template, data=prompt_data)
|
140
|
+
|
141
|
+
if isinstance(validated, str):
|
142
|
+
return validated
|
143
|
+
if isinstance(validated, BaseModel):
|
144
|
+
return validated.model_dump_json(indent=2)
|
145
|
+
if isinstance(validated, dict):
|
146
|
+
return json.dumps(validated, indent=2)
|
147
|
+
|
148
|
+
if validated is None and isinstance(self.instructions, str):
|
149
|
+
return self.instructions
|
150
|
+
|
151
|
+
return str(validated)
|
152
|
+
|
153
|
+
async def invoke(
|
154
|
+
self,
|
155
|
+
*,
|
156
|
+
pipeline: Any,
|
157
|
+
span_name: str,
|
158
|
+
payload: Any = None,
|
159
|
+
prompt: Optional[str] = None,
|
160
|
+
context: Any = None,
|
161
|
+
template: Optional[str] = None,
|
162
|
+
span_type: Optional[str] = None,
|
163
|
+
output_model: Optional[type[BaseModel]] = None,
|
164
|
+
printer_key: Optional[str] = None,
|
165
|
+
printer_title: Optional[str] = None,
|
166
|
+
printer_group_id: Optional[str] = None,
|
167
|
+
printer_border_style: Optional[str] = None,
|
168
|
+
**span_kwargs: Any,
|
169
|
+
) -> Any:
|
170
|
+
instructions = prompt or self.build_prompt(payload, context=context, template=template)
|
171
|
+
model = output_model or self.output_model
|
172
|
+
|
173
|
+
return await pipeline.agent_step(
|
174
|
+
agent=self,
|
175
|
+
instructions=instructions,
|
176
|
+
span_name=span_name,
|
177
|
+
span_type=span_type or self.default_span_type,
|
178
|
+
output_model=model,
|
179
|
+
printer_key=printer_key,
|
180
|
+
printer_title=printer_title,
|
181
|
+
printer_group_id=printer_group_id,
|
182
|
+
printer_border_style=printer_border_style,
|
183
|
+
**span_kwargs,
|
184
|
+
)
|
185
|
+
|
186
|
+
async def __call__(self, payload: Any = None, group_id: Optional[str] = None) -> Any:
|
187
|
+
"""Make ContextAgent callable directly.
|
188
|
+
|
189
|
+
This allows usage like: result = await agent(input_data)
|
190
|
+
|
191
|
+
When called within a pipeline context (self._pipeline is set), uses the
|
192
|
+
pipeline's agent_step for full tracking/tracing. Otherwise, uses ContextRunner.
|
193
|
+
|
194
|
+
Note: When calling directly without pipeline context, input validation
|
195
|
+
is relaxed to allow string inputs even if agent has a defined input_model.
|
196
|
+
|
197
|
+
Args:
|
198
|
+
payload: Input data for the agent
|
199
|
+
group_id: Optional group ID for tracking (used with pipeline context)
|
200
|
+
|
201
|
+
Returns:
|
202
|
+
Parsed output if in pipeline context, otherwise RunResult
|
203
|
+
"""
|
204
|
+
# Build prompt with non-strict input coercion
|
205
|
+
# This allows string inputs to pass through without validation errors
|
206
|
+
validated = self._coerce_input(payload, strict=False)
|
207
|
+
|
208
|
+
if isinstance(validated, str):
|
209
|
+
instructions = validated
|
210
|
+
elif isinstance(validated, BaseModel):
|
211
|
+
instructions = validated.model_dump_json(indent=2)
|
212
|
+
elif isinstance(validated, dict):
|
213
|
+
import json
|
214
|
+
instructions = json.dumps(validated, indent=2)
|
215
|
+
elif validated is None and isinstance(self.instructions, str):
|
216
|
+
instructions = self.instructions
|
217
|
+
else:
|
218
|
+
instructions = str(validated)
|
219
|
+
|
220
|
+
# If pipeline context is available, use it for full tracking
|
221
|
+
if self._pipeline is not None:
|
222
|
+
result = await self._pipeline.agent_step(
|
223
|
+
agent=self,
|
224
|
+
instructions=instructions,
|
225
|
+
group_id=group_id,
|
226
|
+
)
|
227
|
+
# Extract final output for cleaner API
|
228
|
+
output = result.final_output if hasattr(result, 'final_output') else result
|
229
|
+
|
230
|
+
# Automatic iteration tracking based on role
|
231
|
+
if self._role and hasattr(self._pipeline, 'context'):
|
232
|
+
try:
|
233
|
+
iteration = self._pipeline.context.current_iteration
|
234
|
+
|
235
|
+
# Special handling for "observe" role - set iteration.observation
|
236
|
+
if self._role == "observe":
|
237
|
+
serialized = self._pipeline._serialize_output(output)
|
238
|
+
iteration.observation = serialized
|
239
|
+
|
240
|
+
# Record structured payload for all roles
|
241
|
+
self._pipeline._record_structured_payload(output, context_label=self._role)
|
242
|
+
except Exception:
|
243
|
+
# Silently skip if context/iteration not available
|
244
|
+
pass
|
245
|
+
|
246
|
+
return output
|
247
|
+
|
248
|
+
# Otherwise, use ContextRunner to execute the agent
|
249
|
+
from agentz.runner import ContextRunner
|
250
|
+
|
251
|
+
result = await ContextRunner.run(
|
252
|
+
starting_agent=self,
|
253
|
+
input=instructions,
|
254
|
+
)
|
255
|
+
|
256
|
+
return result
|
257
|
+
|
258
|
+
async def parse_output(self, run_result: RunResult) -> RunResult:
|
259
|
+
"""Apply legacy string parser only when no structured output is configured."""
|
260
|
+
if self.output_parser and self.output_model is None:
|
261
|
+
run_result.final_output = self.output_parser(run_result.final_output)
|
262
|
+
return run_result
|