contextagent 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 (66) hide show
  1. agentz/agent/base.py +262 -0
  2. agentz/artifacts/__init__.py +5 -0
  3. agentz/artifacts/artifact_writer.py +538 -0
  4. agentz/artifacts/reporter.py +235 -0
  5. agentz/artifacts/terminal_writer.py +100 -0
  6. agentz/context/__init__.py +6 -0
  7. agentz/context/context.py +91 -0
  8. agentz/context/conversation.py +205 -0
  9. agentz/context/data_store.py +208 -0
  10. agentz/llm/llm_setup.py +156 -0
  11. agentz/mcp/manager.py +142 -0
  12. agentz/mcp/patches.py +88 -0
  13. agentz/mcp/servers/chrome_devtools/server.py +14 -0
  14. agentz/profiles/base.py +108 -0
  15. agentz/profiles/data/data_analysis.py +38 -0
  16. agentz/profiles/data/data_loader.py +35 -0
  17. agentz/profiles/data/evaluation.py +43 -0
  18. agentz/profiles/data/model_training.py +47 -0
  19. agentz/profiles/data/preprocessing.py +47 -0
  20. agentz/profiles/data/visualization.py +47 -0
  21. agentz/profiles/manager/evaluate.py +51 -0
  22. agentz/profiles/manager/memory.py +62 -0
  23. agentz/profiles/manager/observe.py +48 -0
  24. agentz/profiles/manager/routing.py +66 -0
  25. agentz/profiles/manager/writer.py +51 -0
  26. agentz/profiles/mcp/browser.py +21 -0
  27. agentz/profiles/mcp/chrome.py +21 -0
  28. agentz/profiles/mcp/notion.py +21 -0
  29. agentz/runner/__init__.py +74 -0
  30. agentz/runner/base.py +28 -0
  31. agentz/runner/executor.py +320 -0
  32. agentz/runner/hooks.py +110 -0
  33. agentz/runner/iteration.py +142 -0
  34. agentz/runner/patterns.py +215 -0
  35. agentz/runner/tracker.py +188 -0
  36. agentz/runner/utils.py +45 -0
  37. agentz/runner/workflow.py +250 -0
  38. agentz/tools/__init__.py +20 -0
  39. agentz/tools/data_tools/__init__.py +17 -0
  40. agentz/tools/data_tools/data_analysis.py +152 -0
  41. agentz/tools/data_tools/data_loading.py +92 -0
  42. agentz/tools/data_tools/evaluation.py +175 -0
  43. agentz/tools/data_tools/helpers.py +120 -0
  44. agentz/tools/data_tools/model_training.py +192 -0
  45. agentz/tools/data_tools/preprocessing.py +229 -0
  46. agentz/tools/data_tools/visualization.py +281 -0
  47. agentz/utils/__init__.py +69 -0
  48. agentz/utils/config.py +708 -0
  49. agentz/utils/helpers.py +10 -0
  50. agentz/utils/parsers.py +142 -0
  51. agentz/utils/printer.py +539 -0
  52. contextagent-0.1.0.dist-info/METADATA +269 -0
  53. contextagent-0.1.0.dist-info/RECORD +66 -0
  54. contextagent-0.1.0.dist-info/WHEEL +5 -0
  55. contextagent-0.1.0.dist-info/licenses/LICENSE +21 -0
  56. contextagent-0.1.0.dist-info/top_level.txt +2 -0
  57. pipelines/base.py +972 -0
  58. pipelines/data_scientist.py +97 -0
  59. pipelines/data_scientist_memory.py +151 -0
  60. pipelines/experience_learner.py +0 -0
  61. pipelines/prompt_generator.py +0 -0
  62. pipelines/simple.py +78 -0
  63. pipelines/simple_browser.py +145 -0
  64. pipelines/simple_chrome.py +75 -0
  65. pipelines/simple_notion.py +103 -0
  66. pipelines/tool_builder.py +0 -0
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from agentz.profiles.base import Profile
6
+
7
+
8
+ class InstructionsInput(BaseModel):
9
+ """Input schema for instructions-based runtime template."""
10
+ instructions: str = Field(description="The instructions to follow")
11
+
12
+
13
+ # Profile instance for chrome agent
14
+ chrome_profile = Profile(
15
+ instructions="You are a chrome agent. Your task is to interact with the chrome browser following the instructions provided.",
16
+ runtime_template="[[INSTRUCTIONS]]",
17
+ output_schema=None,
18
+ input_schema=InstructionsInput,
19
+ tools=None,
20
+ model=None
21
+ )
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from agentz.profiles.base import Profile
6
+
7
+
8
+ class InstructionsInput(BaseModel):
9
+ """Input schema for instructions-based runtime template."""
10
+ instructions: str = Field(description="The instructions to follow")
11
+
12
+
13
+ # Profile instance for notion agent
14
+ notion_profile = Profile(
15
+ instructions="You are a notion agent. Your task is to interact with the notion MCP server following the instructions provided.",
16
+ runtime_template="[[INSTRUCTIONS]]",
17
+ output_schema=None,
18
+ input_schema=InstructionsInput,
19
+ tools=None,
20
+ model=None
21
+ )
@@ -0,0 +1,74 @@
1
+ """Agent runtime execution module.
2
+
3
+ This module provides the complete agent runtime infrastructure:
4
+
5
+ Base Runners:
6
+ - Runner: Base runner from agents library (re-exported)
7
+ - ContextRunner: Context-aware runner with output parsing
8
+
9
+ Runtime Infrastructure:
10
+ - RuntimeTracker: Manages runtime state (tracing, printing, reporting, iteration tracking, data store)
11
+ - AgentExecutor: High-level agent execution with full pipeline infrastructure
12
+ - AgentStep: Abstraction for a single agent execution step
13
+
14
+ Pipeline Infrastructure:
15
+ - HookRegistry: Event-driven hook system for pipeline lifecycle
16
+ - IterationManager: Iteration management for iterative workflows
17
+ - WorkflowHelpers: Control flow helpers (loops, conditionals, parallel execution)
18
+
19
+ High-Level Patterns:
20
+ - execute_tool_plan: Execute tool agents from routing plans
21
+ - execute_tools: Execute tools based on routing plan
22
+ - run_manager_tool_loop: Standard manager-tool iterative pattern
23
+
24
+ Utilities:
25
+ - record_structured_payload: Record payloads to state
26
+ - serialize_output: Serialize agent outputs
27
+
28
+ Runtime Access:
29
+ - get_current_tracker: Access the current RuntimeTracker from anywhere
30
+ - get_current_data_store: Convenience for accessing the data store
31
+
32
+ """
33
+
34
+ from agentz.runner.base import Runner, ContextRunner
35
+ from agentz.runner.tracker import (
36
+ RuntimeTracker,
37
+ get_current_tracker,
38
+ get_current_data_store,
39
+ )
40
+ from agentz.runner.executor import AgentExecutor, AgentStep, PrinterConfig
41
+ from agentz.runner.hooks import HookRegistry
42
+ from agentz.runner.iteration import IterationManager
43
+ from agentz.runner.workflow import WorkflowHelpers
44
+ from agentz.runner.patterns import (
45
+ execute_tool_plan,
46
+ execute_tools,
47
+ run_manager_tool_loop,
48
+ )
49
+ from agentz.runner.utils import record_structured_payload, serialize_output
50
+
51
+ __all__ = [
52
+ # Base runners
53
+ "Runner",
54
+ "ContextRunner",
55
+ # Runtime infrastructure
56
+ "RuntimeTracker",
57
+ "AgentExecutor",
58
+ "AgentStep",
59
+ "PrinterConfig",
60
+ # Pipeline infrastructure
61
+ "HookRegistry",
62
+ "IterationManager",
63
+ "WorkflowHelpers",
64
+ # High-level patterns
65
+ "execute_tool_plan",
66
+ "execute_tools",
67
+ "run_manager_tool_loop",
68
+ # Utilities
69
+ "record_structured_payload",
70
+ "serialize_output",
71
+ # Runtime access
72
+ "get_current_tracker",
73
+ "get_current_data_store",
74
+ ]
agentz/runner/base.py ADDED
@@ -0,0 +1,28 @@
1
+ """Base runner classes for agent execution.
2
+
3
+ This module provides the foundational runner classes:
4
+ - Runner: Base runner from agents library (re-exported for convenience)
5
+ - ContextRunner: Context-aware runner that applies output parsing
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ from agents import Runner, RunResult
11
+
12
+ __all__ = ["Runner", "ContextRunner"]
13
+
14
+
15
+ class ContextRunner(Runner):
16
+ """Runner shim that invokes ContextAgent.parse_output after execution."""
17
+
18
+ @classmethod
19
+ async def run(cls, *args: Any, **kwargs: Any) -> RunResult:
20
+ result = await Runner.run(*args, **kwargs)
21
+ starting_agent = kwargs.get("starting_agent") or (args[0] if args else None)
22
+
23
+ # Import here to avoid circular dependency
24
+ from agentz.agent.base import ContextAgent
25
+
26
+ if isinstance(starting_agent, ContextAgent):
27
+ return await starting_agent.parse_output(result)
28
+ return result
@@ -0,0 +1,320 @@
1
+ """Core agent execution primitives."""
2
+
3
+ import asyncio
4
+ import json
5
+ import time
6
+ from dataclasses import dataclass, field
7
+ from typing import Any, Callable, Dict, Optional, Union
8
+
9
+ from agentz.runner.base import ContextRunner as Runner
10
+ from agents.tracing.create import agent_span, function_span
11
+ from pydantic import BaseModel
12
+
13
+ from agentz.runner.tracker import RuntimeTracker
14
+
15
+
16
+ @dataclass
17
+ class PrinterConfig:
18
+ """Configuration for printer updates during step execution."""
19
+ key: Optional[str] = None
20
+ title: Optional[str] = None
21
+ start_message: Optional[str] = None
22
+ done_message: Optional[str] = None
23
+
24
+
25
+ @dataclass
26
+ class AgentStep:
27
+ """Represents a single agent execution step.
28
+
29
+ This encapsulates all the information needed to execute an agent:
30
+ - The agent instance
31
+ - Instructions (static or dynamic via callable)
32
+ - Span configuration for tracing
33
+ - Output model for parsing
34
+ - Printer configuration for status updates
35
+ """
36
+
37
+ agent: Any
38
+ instructions: Union[str, Callable[[], str]]
39
+ span_name: str
40
+ span_type: str = "agent"
41
+ output_model: Optional[type[BaseModel]] = None
42
+ sync: bool = False
43
+ printer_config: Optional[PrinterConfig] = None
44
+ span_kwargs: Dict[str, Any] = field(default_factory=dict)
45
+
46
+ def get_instructions(self) -> str:
47
+ """Get instructions, evaluating callable if needed.
48
+
49
+ Returns:
50
+ Instructions string
51
+ """
52
+ if callable(self.instructions):
53
+ return self.instructions()
54
+ return self.instructions
55
+
56
+ def get_printer_key(self, iteration: int = 0) -> Optional[str]:
57
+ """Get the printer key, adding iteration prefix if configured.
58
+
59
+ Args:
60
+ iteration: Current iteration number
61
+
62
+ Returns:
63
+ Printer key with iteration prefix, or None if not configured
64
+ """
65
+ if not self.printer_config or not self.printer_config.key:
66
+ return None
67
+ return f"iter:{iteration}:{self.printer_config.key}"
68
+
69
+
70
+ class AgentExecutor:
71
+ """Core agent execution primitive.
72
+
73
+ Handles the low-level mechanics of running agents with:
74
+ - Span tracking and output capture
75
+ - Optional output model parsing
76
+ - Printer status updates
77
+ - Sync/async execution
78
+ """
79
+
80
+ def __init__(self, context: RuntimeTracker):
81
+ """Initialize executor with runtime tracker.
82
+
83
+ Args:
84
+ context: RuntimeTracker for tracing, printing, etc.
85
+ """
86
+ self.context = context
87
+
88
+ async def execute_step(self, step: AgentStep) -> Any:
89
+ """Execute an AgentStep.
90
+
91
+ Args:
92
+ step: AgentStep to execute
93
+
94
+ Returns:
95
+ Parsed output if output_model provided, otherwise Runner result
96
+ """
97
+ instructions = step.get_instructions()
98
+
99
+ return await self.agent_step(
100
+ agent=step.agent,
101
+ instructions=instructions,
102
+ span_name=step.span_name,
103
+ span_type=step.span_type,
104
+ output_model=step.output_model,
105
+ sync=step.sync,
106
+ printer_key=step.printer_config.key if step.printer_config else None,
107
+ printer_title=step.printer_config.title if step.printer_config else None,
108
+ **step.span_kwargs
109
+ )
110
+
111
+ async def agent_step(
112
+ self,
113
+ agent,
114
+ instructions: str,
115
+ span_name: Optional[str] = None,
116
+ span_type: str = "agent",
117
+ output_model: Optional[type[BaseModel]] = None,
118
+ sync: bool = False,
119
+ printer_key: Optional[str] = None,
120
+ printer_title: Optional[str] = None,
121
+ group_id: Optional[str] = None,
122
+ printer_group_id: Optional[str] = None,
123
+ printer_border_style: Optional[str] = None,
124
+ **span_kwargs
125
+ ) -> Any:
126
+ """Run an agent with span tracking and optional output parsing.
127
+
128
+ Args:
129
+ agent: The agent to run
130
+ instructions: Instructions/prompt for the agent
131
+ span_name: Name for the span (auto-detected from agent.name if not provided)
132
+ span_type: Type of span - "agent" or "function"
133
+ output_model: Optional pydantic model to parse output
134
+ sync: Whether to run synchronously
135
+ printer_key: Optional key for printer updates (auto-detected from agent.name if not provided)
136
+ printer_title: Optional title for printer display (auto-detected from agent.name if not provided)
137
+ group_id: Optional group to nest this item in (alias for printer_group_id)
138
+ printer_group_id: Optional group to nest this item in (deprecated, use group_id)
139
+ printer_border_style: Optional border color
140
+ **span_kwargs: Additional kwargs for span (e.g., tools, input)
141
+
142
+ Returns:
143
+ Parsed output if output_model provided, otherwise Runner result
144
+ """
145
+ # Extract agent name for auto-detection
146
+ agent_name = getattr(agent, "name", getattr(agent, "__class__", type("obj", (), {})).__name__)
147
+
148
+ # Auto-detect span_name from agent if not provided
149
+ if span_name is None:
150
+ span_name = str(agent_name)
151
+
152
+ # Auto-detect printer_key from agent if not provided
153
+ if printer_key is None:
154
+ printer_key = str(agent_name)
155
+
156
+ # Auto-detect printer_title from agent if not provided
157
+ if printer_title is None:
158
+ # Capitalize first letter and add "ing" suffix
159
+ title_base = str(agent_name).capitalize()
160
+ printer_title = f"{title_base}"
161
+
162
+ # Support both group_id and printer_group_id (group_id takes precedence)
163
+ if group_id is not None:
164
+ printer_group_id = group_id
165
+
166
+ span_factory = agent_span if span_type == "agent" else function_span
167
+
168
+ reporter = self.context.reporter
169
+ step_id: Optional[str] = None
170
+ if reporter:
171
+ step_id = f"{self.context.iteration}-{span_name}-{time.time_ns()}"
172
+ reporter.record_agent_step_start(
173
+ step_id=step_id,
174
+ agent_name=str(agent_name),
175
+ span_name=span_name,
176
+ iteration=self.context.iteration,
177
+ group_id=printer_group_id,
178
+ printer_title=printer_title,
179
+ )
180
+
181
+ full_printer_key: Optional[str] = None
182
+ if printer_key:
183
+ full_printer_key = f"iter:{self.context.iteration}:{printer_key}"
184
+ self.context.update_printer(
185
+ full_printer_key,
186
+ "Working...",
187
+ title=printer_title or printer_key,
188
+ border_style=printer_border_style,
189
+ group_id=printer_group_id,
190
+ )
191
+
192
+ status = "success"
193
+ error_message: Optional[str] = None
194
+ start_time = time.perf_counter()
195
+
196
+ try:
197
+ with self.context.span_context(span_factory, name=span_name, **span_kwargs) as span:
198
+ # Activate context so tools can access it
199
+ with self.context.activate():
200
+ if sync:
201
+ result = Runner.run_sync(agent, instructions, context=self.context.data_store)
202
+ else:
203
+ result = await Runner.run(agent, instructions, context=self.context.data_store)
204
+
205
+ raw_output = getattr(result, "final_output", result)
206
+
207
+ # Update printer status and emit detailed output as a standalone panel
208
+ if full_printer_key:
209
+ self.context.update_printer(
210
+ full_printer_key,
211
+ "Completed",
212
+ is_done=True,
213
+ title=printer_title or printer_key,
214
+ group_id=printer_group_id,
215
+ border_style=printer_border_style,
216
+ )
217
+
218
+ # Extract content from raw_output
219
+ if hasattr(raw_output, 'output'):
220
+ panel_content = str(raw_output.output)
221
+ elif isinstance(raw_output, BaseModel):
222
+ panel_content = raw_output.model_dump_json(indent=2)
223
+ elif isinstance(raw_output, dict):
224
+ panel_content = json.dumps(raw_output, indent=2)
225
+ else:
226
+ panel_content = str(raw_output)
227
+
228
+ if panel_content.strip():
229
+ self.context.log_panel(
230
+ printer_title or printer_key,
231
+ panel_content,
232
+ border_style=printer_border_style,
233
+ iteration=self.context.iteration,
234
+ group_id=printer_group_id,
235
+ )
236
+
237
+ if output_model:
238
+ if isinstance(raw_output, output_model):
239
+ output = raw_output
240
+ elif isinstance(raw_output, BaseModel):
241
+ output = output_model.model_validate(raw_output.model_dump())
242
+ elif isinstance(raw_output, (dict, list)):
243
+ output = output_model.model_validate(raw_output)
244
+ elif isinstance(raw_output, (str, bytes, bytearray)):
245
+ output = output_model.model_validate_json(raw_output)
246
+ else:
247
+ output = output_model.model_validate(raw_output)
248
+ if span and hasattr(span, "set_output"):
249
+ span.set_output(output.model_dump())
250
+ return output
251
+ else:
252
+ if span and hasattr(span, "set_output"):
253
+ span.set_output({"output_preview": str(getattr(result, "final_output", result))[:200]})
254
+ return result
255
+ except Exception as exc: # noqa: BLE001 - propagate after logging
256
+ status = "error"
257
+ error_message = str(exc)
258
+ raise
259
+ finally:
260
+ if reporter and step_id is not None:
261
+ reporter.record_agent_step_end(
262
+ step_id=step_id,
263
+ status=status,
264
+ duration_seconds=time.perf_counter() - start_time,
265
+ error=error_message,
266
+ )
267
+
268
+ async def run_span_step(
269
+ self,
270
+ step_key: str,
271
+ callable_or_coro: Union[Callable, Any],
272
+ span_name: str,
273
+ span_type: str = "function",
274
+ start_message: Optional[str] = None,
275
+ done_message: Optional[str] = None,
276
+ **span_kwargs
277
+ ) -> Any:
278
+ """Execute a step with span context and printer updates.
279
+
280
+ Args:
281
+ step_key: Printer status key
282
+ callable_or_coro: Callable or coroutine to execute
283
+ span_name: Name for the span
284
+ span_type: Type of span - "agent" or "function"
285
+ start_message: Optional start message for printer
286
+ done_message: Optional completion message for printer
287
+ **span_kwargs: Additional kwargs for span (e.g., tools, input)
288
+
289
+ Returns:
290
+ Result from callable_or_coro
291
+ """
292
+ span_factory = agent_span if span_type == "agent" else function_span
293
+
294
+ if start_message:
295
+ self.context.update_printer(step_key, start_message)
296
+
297
+ with self.context.span_context(span_factory, name=span_name, **span_kwargs) as span:
298
+ # Execute callable or await coroutine
299
+ if asyncio.iscoroutine(callable_or_coro):
300
+ result = await callable_or_coro
301
+ elif callable(callable_or_coro):
302
+ result = callable_or_coro()
303
+ else:
304
+ result = callable_or_coro
305
+
306
+ # Set span output if available
307
+ if span and hasattr(span, "set_output"):
308
+ if isinstance(result, dict):
309
+ span.set_output(result)
310
+ elif isinstance(result, str):
311
+ span.set_output({"output_preview": result[:200]})
312
+ elif hasattr(result, "model_dump"):
313
+ span.set_output(result.model_dump())
314
+ else:
315
+ span.set_output({"result": str(result)[:200]})
316
+
317
+ if done_message:
318
+ self.context.update_printer(step_key, done_message, is_done=True)
319
+
320
+ return result
agentz/runner/hooks.py ADDED
@@ -0,0 +1,110 @@
1
+ """Hook registry system for event-driven pipeline extensibility."""
2
+
3
+ import asyncio
4
+ from typing import Any, Callable, Dict, List, Tuple
5
+
6
+ from loguru import logger
7
+
8
+
9
+ class HookRegistry:
10
+ """Registry for managing pipeline event hooks.
11
+
12
+ Supports registering callbacks for various lifecycle events and triggering
13
+ them with priority ordering.
14
+ """
15
+
16
+ DEFAULT_EVENTS = [
17
+ "before_execution",
18
+ "after_execution",
19
+ "before_iteration",
20
+ "after_iteration",
21
+ "before_agent_step",
22
+ "after_agent_step",
23
+ ]
24
+
25
+ def __init__(self, events: List[str] = None):
26
+ """Initialize hook registry.
27
+
28
+ Args:
29
+ events: List of event names to support (defaults to DEFAULT_EVENTS)
30
+ """
31
+ event_list = events or self.DEFAULT_EVENTS
32
+ self._hooks: Dict[str, List[Tuple[int, Callable]]] = {
33
+ event: [] for event in event_list
34
+ }
35
+
36
+ def register(
37
+ self,
38
+ event: str,
39
+ callback: Callable,
40
+ priority: int = 0
41
+ ) -> None:
42
+ """Register a hook callback for an event.
43
+
44
+ Args:
45
+ event: Event name
46
+ callback: Callable or async callable
47
+ priority: Execution priority (higher = earlier)
48
+
49
+ Raises:
50
+ ValueError: If event is not recognized
51
+
52
+ Example:
53
+ def log_iteration(pipeline, iteration, group_id):
54
+ logger.info(f"Starting iteration {iteration.index}")
55
+
56
+ registry.register("before_iteration", log_iteration)
57
+ """
58
+ if event not in self._hooks:
59
+ raise ValueError(
60
+ f"Unknown hook event: {event}. Valid events: {list(self._hooks.keys())}"
61
+ )
62
+
63
+ self._hooks[event].append((priority, callback))
64
+ # Sort by priority (descending)
65
+ self._hooks[event].sort(key=lambda x: -x[0])
66
+
67
+ async def trigger(self, event: str, context: Any, **kwargs) -> None:
68
+ """Trigger all registered hooks for an event.
69
+
70
+ Args:
71
+ event: Event name
72
+ context: Context object to pass to callbacks (typically the pipeline)
73
+ **kwargs: Additional arguments to pass to hook callbacks
74
+ """
75
+ if event not in self._hooks:
76
+ return
77
+
78
+ for priority, callback in self._hooks[event]:
79
+ try:
80
+ if asyncio.iscoroutinefunction(callback):
81
+ await callback(context, **kwargs)
82
+ else:
83
+ callback(context, **kwargs)
84
+ except Exception as e:
85
+ logger.warning(f"Hook {callback.__name__} for {event} failed: {e}")
86
+
87
+ def has_hooks(self, event: str) -> bool:
88
+ """Check if any hooks are registered for an event.
89
+
90
+ Args:
91
+ event: Event name
92
+
93
+ Returns:
94
+ True if hooks are registered, False otherwise
95
+ """
96
+ return event in self._hooks and len(self._hooks[event]) > 0
97
+
98
+ def clear_event(self, event: str) -> None:
99
+ """Clear all hooks for a specific event.
100
+
101
+ Args:
102
+ event: Event name
103
+ """
104
+ if event in self._hooks:
105
+ self._hooks[event].clear()
106
+
107
+ def clear_all(self) -> None:
108
+ """Clear all registered hooks."""
109
+ for event in self._hooks:
110
+ self._hooks[event].clear()