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,142 @@
1
+ """Iteration management for iterative pipeline workflows."""
2
+
3
+ import time
4
+ from typing import Any, Optional, Tuple
5
+
6
+ from loguru import logger
7
+
8
+
9
+ class IterationManager:
10
+ """Manages iteration lifecycle for iterative pipelines.
11
+
12
+ Handles:
13
+ - Starting/ending iterations with printer groups
14
+ - Constraint checking (max iterations, max time)
15
+ - Final group management
16
+ """
17
+
18
+ # Constants for iteration group IDs
19
+ ITERATION_GROUP_PREFIX = "iter"
20
+ FINAL_GROUP_ID = "iter-final"
21
+
22
+ def __init__(
23
+ self,
24
+ context: Any,
25
+ max_iterations: int = 5,
26
+ max_time_minutes: float = 10,
27
+ start_group_callback: Optional[callable] = None,
28
+ end_group_callback: Optional[callable] = None,
29
+ ):
30
+ """Initialize iteration manager.
31
+
32
+ Args:
33
+ context: Pipeline context with state and begin_iteration/mark_iteration_complete methods
34
+ max_iterations: Maximum number of iterations allowed
35
+ max_time_minutes: Maximum time in minutes
36
+ start_group_callback: Optional callback(group_id, title, border_style, iteration)
37
+ end_group_callback: Optional callback(group_id, is_done, title)
38
+ """
39
+ self.context = context
40
+ self.max_iterations = max_iterations
41
+ self.max_time_minutes = max_time_minutes
42
+ self.start_group_callback = start_group_callback
43
+ self.end_group_callback = end_group_callback
44
+
45
+ self.start_time: Optional[float] = None
46
+ self.current_iteration: int = 0
47
+
48
+ def start_timer(self) -> None:
49
+ """Start the iteration timer for constraint checking."""
50
+ self.start_time = time.time()
51
+
52
+ def begin_iteration(self) -> Tuple[Any, str]:
53
+ """Begin a new iteration with printer group.
54
+
55
+ Returns:
56
+ Tuple of (iteration_record, group_id)
57
+ """
58
+ iteration = self.context.begin_iteration()
59
+ group_id = f"{self.ITERATION_GROUP_PREFIX}-{iteration.index}"
60
+
61
+ self.current_iteration = iteration.index
62
+
63
+ if self.start_group_callback:
64
+ self.start_group_callback(
65
+ group_id,
66
+ title=f"Iteration {iteration.index}",
67
+ border_style="white",
68
+ iteration=iteration.index,
69
+ )
70
+
71
+ return iteration, group_id
72
+
73
+ def end_iteration(self, group_id: str) -> None:
74
+ """End the current iteration and close printer group.
75
+
76
+ Args:
77
+ group_id: Group ID to close
78
+ """
79
+ self.context.mark_iteration_complete()
80
+
81
+ if self.end_group_callback:
82
+ self.end_group_callback(group_id, is_done=True)
83
+
84
+ def start_final_group(self) -> str:
85
+ """Start final group for post-iteration work.
86
+
87
+ Returns:
88
+ Final group ID
89
+ """
90
+ if self.start_group_callback:
91
+ self.start_group_callback(
92
+ self.FINAL_GROUP_ID,
93
+ title="Final Report",
94
+ border_style="white",
95
+ )
96
+ return self.FINAL_GROUP_ID
97
+
98
+ def end_final_group(self, group_id: str) -> None:
99
+ """End final group.
100
+
101
+ Args:
102
+ group_id: Group ID to close
103
+ """
104
+ if self.end_group_callback:
105
+ self.end_group_callback(group_id, is_done=True)
106
+
107
+ def should_continue_iteration(self) -> bool:
108
+ """Check if iteration should continue.
109
+
110
+ Checks:
111
+ - State not complete
112
+ - Within max iterations
113
+ - Within max time
114
+
115
+ Returns:
116
+ True if should continue, False otherwise
117
+ """
118
+ # Check state completion
119
+ if hasattr(self.context, 'state') and self.context.state and self.context.state.complete:
120
+ return False
121
+
122
+ return self.check_constraints()
123
+
124
+ def check_constraints(self) -> bool:
125
+ """Check if we've exceeded our constraints (max iterations or time).
126
+
127
+ Returns:
128
+ True if within constraints, False if exceeded
129
+ """
130
+ if self.current_iteration >= self.max_iterations:
131
+ logger.info("\n=== Ending Iteration Loop ===")
132
+ logger.info(f"Reached maximum iterations ({self.max_iterations})")
133
+ return False
134
+
135
+ if self.start_time is not None:
136
+ elapsed_minutes = (time.time() - self.start_time) / 60
137
+ if elapsed_minutes >= self.max_time_minutes:
138
+ logger.info("\n=== Ending Iteration Loop ===")
139
+ logger.info(f"Reached maximum time ({self.max_time_minutes} minutes)")
140
+ return False
141
+
142
+ return True
@@ -0,0 +1,215 @@
1
+ """High-level execution patterns for common pipeline workflows."""
2
+
3
+ import asyncio
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ from loguru import logger
7
+
8
+ from agentz.runner.utils import record_structured_payload, serialize_output
9
+
10
+
11
+ async def execute_tool_plan(
12
+ plan: Any,
13
+ tool_agents: Dict[str, Any],
14
+ group_id: str,
15
+ context: Any,
16
+ agent_step_fn: Any,
17
+ update_printer_fn: Optional[Any] = None,
18
+ ) -> None:
19
+ """Execute a routing plan with tool agents.
20
+
21
+ Args:
22
+ plan: AgentSelectionPlan with tasks to execute
23
+ tool_agents: Dict mapping agent names to agent instances
24
+ group_id: Group ID for printer updates
25
+ context: Pipeline context with state
26
+ agent_step_fn: Function to execute agent steps
27
+ update_printer_fn: Optional function for printer updates
28
+ """
29
+ # Import here to avoid circular dependency
30
+ from agentz.profiles.manager.routing import AgentSelectionPlan, AgentTask
31
+ from agentz.profiles.base import ToolAgentOutput
32
+
33
+ if not isinstance(plan, AgentSelectionPlan) or not plan.tasks:
34
+ return
35
+
36
+ state = context.state
37
+ state.current_iteration.tools.clear()
38
+
39
+ async def run_single(task: AgentTask) -> ToolAgentOutput:
40
+ agent = tool_agents.get(task.agent)
41
+ if agent is None:
42
+ output = ToolAgentOutput(
43
+ output=f"No implementation found for agent {task.agent}",
44
+ sources=[],
45
+ )
46
+ if update_printer_fn:
47
+ update_printer_fn(
48
+ key=f"{group_id}:tool:{task.agent}",
49
+ message=f"Completed {task.agent}",
50
+ is_done=True,
51
+ group_id=group_id,
52
+ )
53
+ return output
54
+
55
+ raw_result = await agent_step_fn(
56
+ agent=agent,
57
+ instructions=task.model_dump_json(),
58
+ span_name=task.agent,
59
+ span_type="tool",
60
+ output_model=ToolAgentOutput,
61
+ printer_key=f"tool:{task.agent}",
62
+ printer_title=f"Tool: {task.agent}",
63
+ printer_group_id=group_id,
64
+ )
65
+
66
+ if isinstance(raw_result, ToolAgentOutput):
67
+ output = raw_result
68
+ elif hasattr(raw_result, "final_output_as"):
69
+ output = raw_result.final_output_as(ToolAgentOutput)
70
+ elif hasattr(raw_result, "final_output"):
71
+ output = ToolAgentOutput(output=str(raw_result.final_output), sources=[])
72
+ else:
73
+ output = ToolAgentOutput(output=str(raw_result), sources=[])
74
+
75
+ try:
76
+ state.record_payload(output)
77
+ except Exception as exc:
78
+ logger.debug(f"Failed to record tool payload for {task.agent}: {exc}")
79
+
80
+ if update_printer_fn:
81
+ update_printer_fn(
82
+ key=f"{group_id}:tool:{task.agent}",
83
+ message=f"Completed {task.agent}",
84
+ is_done=True,
85
+ group_id=group_id,
86
+ )
87
+ return output
88
+
89
+ coroutines = [run_single(task) for task in plan.tasks]
90
+ for coro in asyncio.as_completed(coroutines):
91
+ tool_output = await coro
92
+ state.current_iteration.tools.append(tool_output)
93
+
94
+
95
+ async def execute_tools(
96
+ route_plan: Any,
97
+ tool_agents: Dict[str, Any],
98
+ group_id: str,
99
+ context: Any,
100
+ agent_step_fn: Any,
101
+ update_printer_fn: Optional[Any] = None,
102
+ ) -> None:
103
+ """Execute tool agents based on routing plan.
104
+
105
+ Args:
106
+ route_plan: The routing plan (can be AgentSelectionPlan or other)
107
+ tool_agents: Dict mapping agent names to agent instances
108
+ group_id: Group ID for printer updates
109
+ context: Pipeline context with state
110
+ agent_step_fn: Function to execute agent steps
111
+ update_printer_fn: Optional function for printer updates
112
+ """
113
+ from agentz.profiles.manager.routing import AgentSelectionPlan
114
+
115
+ # Retrieve route_plan from payloads if needed
116
+ plan = None
117
+ if isinstance(route_plan, AgentSelectionPlan):
118
+ plan = route_plan
119
+ elif route_plan and hasattr(context, 'state'):
120
+ # Try to find AgentSelectionPlan in payloads
121
+ for payload in context.state.current_iteration.payloads:
122
+ if isinstance(payload, AgentSelectionPlan):
123
+ plan = payload
124
+ break
125
+
126
+ if plan and plan.tasks:
127
+ await execute_tool_plan(
128
+ plan, tool_agents, group_id, context, agent_step_fn, update_printer_fn
129
+ )
130
+
131
+
132
+ async def run_manager_tool_loop(
133
+ manager_agents: Dict[str, Any],
134
+ tool_agents: Dict[str, Any],
135
+ workflow: List[str],
136
+ context: Any,
137
+ agent_step_fn: Any,
138
+ run_iterative_loop_fn: Any,
139
+ update_printer_fn: Optional[Any] = None,
140
+ ) -> Any:
141
+ """Execute standard manager-tool iterative pattern.
142
+
143
+ This pattern implements: observe → evaluate → route → execute tools → repeat.
144
+
145
+ Args:
146
+ manager_agents: Dict of manager agents (observe, evaluate, routing, writer)
147
+ tool_agents: Dict of tool agents
148
+ workflow: List of manager agent names to execute in order (e.g., ["observe", "evaluate", "routing"])
149
+ context: Pipeline context with state
150
+ agent_step_fn: Function to execute agent steps
151
+ run_iterative_loop_fn: Function to run iterative loop
152
+ update_printer_fn: Optional function for printer updates
153
+
154
+ Returns:
155
+ Result from final step
156
+
157
+ Example:
158
+ result = await run_manager_tool_loop(
159
+ manager_agents=self.manager_agents,
160
+ tool_agents=self.tool_agents,
161
+ workflow=["observe", "evaluate", "routing"],
162
+ context=self.context,
163
+ agent_step_fn=self.agent_step,
164
+ run_iterative_loop_fn=self.run_iterative_loop,
165
+ update_printer_fn=self.update_printer,
166
+ )
167
+ """
168
+ async def iteration_step(iteration, group_id: str):
169
+ """Execute manager workflow + tool execution."""
170
+ previous_output = context.state.query
171
+
172
+ # Execute manager workflow in sequence
173
+ for agent_name in workflow:
174
+ agent = manager_agents.get(agent_name)
175
+ if agent is None:
176
+ logger.warning(f"Manager agent '{agent_name}' not found, skipping")
177
+ continue
178
+
179
+ output = await agent(previous_output)
180
+
181
+ # Record observation for first step
182
+ if agent_name == workflow[0]:
183
+ iteration.observation = serialize_output(output)
184
+
185
+ record_structured_payload(context.state, output, context_label=agent_name)
186
+ previous_output = output
187
+
188
+ # Execute tools if not complete
189
+ if not context.state.complete and previous_output:
190
+ await execute_tools(
191
+ previous_output,
192
+ tool_agents,
193
+ group_id,
194
+ context,
195
+ agent_step_fn,
196
+ update_printer_fn,
197
+ )
198
+
199
+ async def final_step(final_group: str):
200
+ """Generate final report."""
201
+ if update_printer_fn:
202
+ update_printer_fn("research", "Research workflow complete", is_done=True)
203
+ logger.info("Research workflow completed")
204
+
205
+ writer = manager_agents.get("writer")
206
+ if writer:
207
+ await writer(context.state.findings_text())
208
+
209
+ if update_printer_fn:
210
+ update_printer_fn("research", "Executing research workflow...")
211
+
212
+ return await run_iterative_loop_fn(
213
+ iteration_body=iteration_step,
214
+ final_body=final_step
215
+ )
@@ -0,0 +1,188 @@
1
+ """Runtime state tracking for agent execution operations."""
2
+
3
+ from contextlib import nullcontext, contextmanager
4
+ from contextvars import ContextVar
5
+ from typing import Any, Dict, Optional
6
+
7
+ from agents.tracing.create import trace
8
+ from agentz.utils import Printer
9
+ from agentz.context.data_store import DataStore
10
+ from agentz.artifacts import RunReporter
11
+
12
+ # Context variable to store the current runtime tracker
13
+ # This allows tools to access the tracker without explicit parameter passing
14
+ _current_runtime_tracker: ContextVar[Optional['RuntimeTracker']] = ContextVar(
15
+ 'current_runtime_tracker',
16
+ default=None
17
+ )
18
+
19
+
20
+ class RuntimeTracker:
21
+ """Manages runtime state and tracking for agent execution.
22
+
23
+ This class encapsulates the runtime infrastructure needed for agent execution including:
24
+ - Tracing configuration and context creation
25
+ - Printer for status updates
26
+ - Reporter for recording execution events
27
+ - Iteration tracking
28
+ - Pipeline-scoped data store for sharing objects between agents
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ printer: Optional[Printer] = None,
34
+ enable_tracing: bool = True,
35
+ trace_sensitive: bool = False,
36
+ iteration: int = 0,
37
+ experiment_id: Optional[str] = None,
38
+ reporter: Optional[RunReporter] = None,
39
+ ):
40
+ """Initialize runtime tracker.
41
+
42
+ Args:
43
+ printer: Optional Printer instance for status updates
44
+ enable_tracing: Whether tracing is enabled
45
+ trace_sensitive: Whether to include sensitive data in traces
46
+ iteration: Current iteration number (for iterative workflows)
47
+ experiment_id: Optional experiment ID for data store tracking
48
+ reporter: Optional reporter for recording execution events
49
+ """
50
+ self.printer = printer
51
+ self.enable_tracing = enable_tracing
52
+ self.trace_sensitive = trace_sensitive
53
+ self.iteration = iteration
54
+ self.reporter = reporter
55
+ self.data_store = DataStore(experiment_id=experiment_id)
56
+
57
+ def trace_context(self, name: str, metadata: Optional[Dict[str, Any]] = None):
58
+ """Create a trace context manager.
59
+
60
+ Args:
61
+ name: Name for the trace
62
+ metadata: Optional metadata to attach to trace
63
+
64
+ Returns:
65
+ Trace context manager if tracing enabled, otherwise nullcontext
66
+ """
67
+ if self.enable_tracing:
68
+ return trace(name, metadata=metadata)
69
+ return nullcontext()
70
+
71
+ def span_context(self, span_factory, **kwargs):
72
+ """Create a span context manager.
73
+
74
+ Args:
75
+ span_factory: Factory function for creating spans (agent_span or function_span)
76
+ **kwargs: Arguments to pass to span factory
77
+
78
+ Returns:
79
+ Span context manager if tracing enabled, otherwise nullcontext
80
+ """
81
+ if self.enable_tracing:
82
+ return span_factory(**kwargs)
83
+ return nullcontext()
84
+
85
+ def update_printer(
86
+ self,
87
+ key: str,
88
+ message: str,
89
+ is_done: bool = False,
90
+ hide_checkmark: bool = False,
91
+ title: Optional[str] = None,
92
+ border_style: Optional[str] = None,
93
+ group_id: Optional[str] = None,
94
+ ) -> None:
95
+ """Update printer status if printer is active.
96
+
97
+ Args:
98
+ key: Status key to update
99
+ message: Status message
100
+ is_done: Whether the task is complete
101
+ hide_checkmark: Whether to hide the checkmark when done
102
+ title: Optional panel title
103
+ border_style: Optional border color
104
+ group_id: Optional group to nest this item in
105
+ """
106
+ if self.reporter:
107
+ self.reporter.record_status_update(
108
+ item_id=key,
109
+ content=message,
110
+ is_done=is_done,
111
+ title=title,
112
+ border_style=border_style,
113
+ group_id=group_id,
114
+ )
115
+ if self.printer:
116
+ self.printer.update_item(
117
+ key,
118
+ message,
119
+ is_done=is_done,
120
+ hide_checkmark=hide_checkmark,
121
+ title=title,
122
+ border_style=border_style,
123
+ group_id=group_id
124
+ )
125
+
126
+ def log_panel(
127
+ self,
128
+ title: str,
129
+ content: str,
130
+ *,
131
+ border_style: Optional[str] = None,
132
+ iteration: Optional[int] = None,
133
+ group_id: Optional[str] = None,
134
+ ) -> None:
135
+ """Proxy helper for rendering standalone panels via the printer."""
136
+ if self.reporter:
137
+ self.reporter.record_panel(
138
+ title=title,
139
+ content=content,
140
+ border_style=border_style,
141
+ iteration=iteration,
142
+ group_id=group_id,
143
+ )
144
+ if self.printer:
145
+ self.printer.log_panel(
146
+ title,
147
+ content,
148
+ border_style=border_style,
149
+ iteration=iteration,
150
+ )
151
+
152
+ @contextmanager
153
+ def activate(self):
154
+ """Context manager to set this tracker as the current runtime tracker.
155
+
156
+ This allows tools to access the tracker via get_current_tracker().
157
+
158
+ Example:
159
+ with tracker.activate():
160
+ # Tools can now access this tracker
161
+ result = await agent.run(...)
162
+ """
163
+ token = _current_runtime_tracker.set(self)
164
+ try:
165
+ yield self
166
+ finally:
167
+ _current_runtime_tracker.reset(token)
168
+
169
+
170
+ def get_current_tracker() -> Optional[RuntimeTracker]:
171
+ """Get the current runtime tracker (if any).
172
+
173
+ Returns:
174
+ The current RuntimeTracker or None if not in a runtime context
175
+ """
176
+ return _current_runtime_tracker.get()
177
+
178
+
179
+ def get_current_data_store() -> Optional[DataStore]:
180
+ """Get the data store from the current runtime tracker (if any).
181
+
182
+ This is a convenience function for tools that need to access the data store.
183
+
184
+ Returns:
185
+ The current DataStore or None if not in a runtime context
186
+ """
187
+ tracker = get_current_tracker()
188
+ return tracker.data_store if tracker else None
agentz/runner/utils.py ADDED
@@ -0,0 +1,45 @@
1
+ """Utility functions for pipeline execution."""
2
+
3
+ from typing import Any, Optional
4
+
5
+ from loguru import logger
6
+ from pydantic import BaseModel
7
+
8
+
9
+ def record_structured_payload(
10
+ state: Any,
11
+ value: object,
12
+ context_label: Optional[str] = None
13
+ ) -> None:
14
+ """Record a structured payload to the current iteration state.
15
+
16
+ Args:
17
+ state: The state object (typically from context.state)
18
+ value: The payload to record (typically a BaseModel instance)
19
+ context_label: Optional label for debugging purposes
20
+ """
21
+ if isinstance(value, BaseModel):
22
+ try:
23
+ if state:
24
+ state.record_payload(value)
25
+ except Exception as exc:
26
+ if context_label:
27
+ logger.debug(f"Failed to record payload for {context_label}: {exc}")
28
+ else:
29
+ logger.debug(f"Failed to record payload: {exc}")
30
+
31
+
32
+ def serialize_output(output: Any) -> str:
33
+ """Serialize agent output to string for storage.
34
+
35
+ Args:
36
+ output: The output to serialize (BaseModel, str, or other)
37
+
38
+ Returns:
39
+ String representation of the output
40
+ """
41
+ if isinstance(output, BaseModel):
42
+ return output.model_dump_json(indent=2)
43
+ elif isinstance(output, str):
44
+ return output
45
+ return str(output)