agex 0.1.0__tar.gz

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 (86) hide show
  1. agex-0.1.0/LICENSE +21 -0
  2. agex-0.1.0/PKG-INFO +114 -0
  3. agex-0.1.0/README.md +53 -0
  4. agex-0.1.0/agex/__init__.py +60 -0
  5. agex-0.1.0/agex/agent/__init__.py +86 -0
  6. agex-0.1.0/agex/agent/base.py +126 -0
  7. agex-0.1.0/agex/agent/console.py +369 -0
  8. agex-0.1.0/agex/agent/conversation.py +94 -0
  9. agex-0.1.0/agex/agent/datatypes.py +131 -0
  10. agex-0.1.0/agex/agent/events.py +613 -0
  11. agex-0.1.0/agex/agent/fingerprint.py +172 -0
  12. agex-0.1.0/agex/agent/formatting.py +88 -0
  13. agex-0.1.0/agex/agent/loop.py +514 -0
  14. agex-0.1.0/agex/agent/policy/__init__.py +27 -0
  15. agex-0.1.0/agex/agent/policy/datatypes.py +99 -0
  16. agex-0.1.0/agex/agent/policy/describe.py +449 -0
  17. agex-0.1.0/agex/agent/policy/policy.py +193 -0
  18. agex-0.1.0/agex/agent/policy/resolve.py +287 -0
  19. agex-0.1.0/agex/agent/primer_text.py +443 -0
  20. agex-0.1.0/agex/agent/registration.py +368 -0
  21. agex-0.1.0/agex/agent/task.py +486 -0
  22. agex-0.1.0/agex/agent/task.pyi +64 -0
  23. agex-0.1.0/agex/agent/task_messages.py +104 -0
  24. agex-0.1.0/agex/agent/utils.py +93 -0
  25. agex-0.1.0/agex/bench/__init__.py +78 -0
  26. agex-0.1.0/agex/bench/aggregators.py +110 -0
  27. agex-0.1.0/agex/bench/core.py +299 -0
  28. agex-0.1.0/agex/bench/types.py +106 -0
  29. agex-0.1.0/agex/eval/analysis.py +103 -0
  30. agex-0.1.0/agex/eval/arguments.py +102 -0
  31. agex-0.1.0/agex/eval/base.py +155 -0
  32. agex-0.1.0/agex/eval/binop.py +147 -0
  33. agex-0.1.0/agex/eval/builtins.py +548 -0
  34. agex-0.1.0/agex/eval/call.py +276 -0
  35. agex-0.1.0/agex/eval/comprehension.py +79 -0
  36. agex-0.1.0/agex/eval/constants.py +42 -0
  37. agex-0.1.0/agex/eval/core.py +126 -0
  38. agex-0.1.0/agex/eval/error.py +22 -0
  39. agex-0.1.0/agex/eval/expressions.py +124 -0
  40. agex-0.1.0/agex/eval/functions.py +392 -0
  41. agex-0.1.0/agex/eval/loops.py +102 -0
  42. agex-0.1.0/agex/eval/objects.py +337 -0
  43. agex-0.1.0/agex/eval/resolver.py +251 -0
  44. agex-0.1.0/agex/eval/safe.py +125 -0
  45. agex-0.1.0/agex/eval/statements.py +679 -0
  46. agex-0.1.0/agex/eval/user_errors.py +78 -0
  47. agex-0.1.0/agex/eval/utils.py +62 -0
  48. agex-0.1.0/agex/eval/validation.py +180 -0
  49. agex-0.1.0/agex/helpers/__init__.py +23 -0
  50. agex-0.1.0/agex/helpers/numpy_helper.py +45 -0
  51. agex-0.1.0/agex/helpers/pandas_helper.py +42 -0
  52. agex-0.1.0/agex/helpers/plotly_helper.py +54 -0
  53. agex-0.1.0/agex/helpers/stdlib.py +69 -0
  54. agex-0.1.0/agex/llm/__init__.py +88 -0
  55. agex-0.1.0/agex/llm/anthropic_client.py +159 -0
  56. agex-0.1.0/agex/llm/config.py +51 -0
  57. agex-0.1.0/agex/llm/core.py +102 -0
  58. agex-0.1.0/agex/llm/dummy_client.py +81 -0
  59. agex-0.1.0/agex/llm/gemini_client.py +148 -0
  60. agex-0.1.0/agex/llm/openai_client.py +94 -0
  61. agex-0.1.0/agex/py.typed +0 -0
  62. agex-0.1.0/agex/render/context.py +51 -0
  63. agex-0.1.0/agex/render/definitions.py +917 -0
  64. agex-0.1.0/agex/render/stream.py +222 -0
  65. agex-0.1.0/agex/render/value.py +387 -0
  66. agex-0.1.0/agex/render/view.py +87 -0
  67. agex-0.1.0/agex/state/__init__.py +79 -0
  68. agex-0.1.0/agex/state/closure.py +123 -0
  69. agex-0.1.0/agex/state/core.py +61 -0
  70. agex-0.1.0/agex/state/kv.py +163 -0
  71. agex-0.1.0/agex/state/live.py +47 -0
  72. agex-0.1.0/agex/state/log.py +67 -0
  73. agex-0.1.0/agex/state/namespaced.py +74 -0
  74. agex-0.1.0/agex/state/scoped.py +55 -0
  75. agex-0.1.0/agex/state/transient.py +97 -0
  76. agex-0.1.0/agex/state/versioned.py +272 -0
  77. agex-0.1.0/agex/tokenizers/__init__.py +11 -0
  78. agex-0.1.0/agex/tokenizers/core.py +16 -0
  79. agex-0.1.0/agex/tokenizers/tiktoken.py +20 -0
  80. agex-0.1.0/agex.egg-info/PKG-INFO +114 -0
  81. agex-0.1.0/agex.egg-info/SOURCES.txt +84 -0
  82. agex-0.1.0/agex.egg-info/dependency_links.txt +1 -0
  83. agex-0.1.0/agex.egg-info/requires.txt +43 -0
  84. agex-0.1.0/agex.egg-info/top_level.txt +2 -0
  85. agex-0.1.0/pyproject.toml +101 -0
  86. agex-0.1.0/setup.cfg +4 -0
agex-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 ashenfad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
agex-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: agex
3
+ Version: 0.1.0
4
+ Summary: Library-friendly agents that work directly with your existing Python codebase.
5
+ Author: ashenfad
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://ashenfad.github.io/agex/
8
+ Project-URL: Documentation, https://ashenfad.github.io/agex/
9
+ Project-URL: Repository, https://github.com/ashenfad/agex
10
+ Project-URL: Issues, https://github.com/ashenfad/agex/issues
11
+ Keywords: agents,ai,llm,python,runtime,sandbox
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: tiktoken
25
+ Requires-Dist: xxhash
26
+ Requires-Dist: diskcache
27
+ Requires-Dist: pydantic
28
+ Requires-Dist: pygments
29
+ Provides-Extra: dev
30
+ Requires-Dist: ruff; extra == "dev"
31
+ Requires-Dist: pre-commit; extra == "dev"
32
+ Requires-Dist: pytest; extra == "dev"
33
+ Provides-Extra: test
34
+ Requires-Dist: pytest; extra == "test"
35
+ Requires-Dist: anyio; extra == "test"
36
+ Requires-Dist: numpy; extra == "test"
37
+ Requires-Dist: pandas; extra == "test"
38
+ Requires-Dist: anthropic; extra == "test"
39
+ Requires-Dist: google-generativeai; extra == "test"
40
+ Requires-Dist: openai; extra == "test"
41
+ Requires-Dist: matplotlib; extra == "test"
42
+ Provides-Extra: examples
43
+ Requires-Dist: plotly[express]; extra == "examples"
44
+ Requires-Dist: kaleido; extra == "examples"
45
+ Requires-Dist: numpy; extra == "examples"
46
+ Requires-Dist: nbformat; extra == "examples"
47
+ Requires-Dist: pandas; extra == "examples"
48
+ Requires-Dist: osmnx>=2.0.0; extra == "examples"
49
+ Requires-Dist: folium; extra == "examples"
50
+ Provides-Extra: openai
51
+ Requires-Dist: openai; extra == "openai"
52
+ Provides-Extra: anthropic
53
+ Requires-Dist: anthropic; extra == "anthropic"
54
+ Provides-Extra: gemini
55
+ Requires-Dist: google-generativeai; extra == "gemini"
56
+ Provides-Extra: all-providers
57
+ Requires-Dist: agex[openai]; extra == "all-providers"
58
+ Requires-Dist: agex[anthropic]; extra == "all-providers"
59
+ Requires-Dist: agex[gemini]; extra == "all-providers"
60
+ Dynamic: license-file
61
+
62
+ # agex: Library-Friendly Agents
63
+
64
+ **`agex`** (a portmanteau of **age**nt **ex**ecution) is a Python-native agentic framework that enables AI agents to work directly with your existing libraries and codebase.
65
+
66
+ ![agex demo gif](docs/assets/teaser.gif)
67
+
68
+ **This works because** `agex` agents can accept and return complex types like `pandas.DataFrame` and `plotly.Figure` objects without intermediate JSON serialization. For a deeper dive, check out the full **[agex101.ipynb tutorial](https://ashenfad.github.io/agex/examples/agex101/)** or see **[geospatial routing with OSMnx](https://ashenfad.github.io/agex/examples/routing/)** for advanced multi-library integration.
69
+
70
+ ## What Makes This Different
71
+
72
+ `agex` uses a subset of Python as the agent action space, executing actions in a sandboxed environment within your process. This approach avoids the complexity of JSON serialization and allows complex objects to flow directly between your code and the agent. You control exactly what functions, classes, and modules are available, creating a powerful yet secure environment.
73
+
74
+ - **Code-as-Action**: Secure, sandboxed Python execution for agents.
75
+ - **Library Integration**: Use your existing code directly, no tool-making required.
76
+ - **Workspace Persistence**: Git-like versioning for agent state and memory.
77
+ - **Multi-Agent**: Orchestrate agents with natural Python control flow.
78
+ - **Event Streams**: Real-time, notebook-friendly observability.
79
+ - **Benchmarking**: A framework for data-driven agent evaluation.
80
+
81
+ ## Documentation
82
+
83
+ Complete documentation is hosted at **[ashenfad.github.io/agex](https://ashenfad.github.io/agex/)**.
84
+
85
+ Key sections:
86
+ - **[📚 Quick Start Guide](https://ashenfad.github.io/agex/quick-start/)**
87
+ - **[🔭 The Big Picture](https://ashenfad.github.io/agex/concepts/big-picture/)**
88
+ - **[💡 Examples](https://ashenfad.github.io/agex/examples/overview/)**
89
+ - **[📖 API Reference](https://ashenfad.github.io/agex/api/overview/)**
90
+
91
+ ## Installation
92
+
93
+ Install agex with your preferred LLM provider:
94
+
95
+ ```bash
96
+ # Install with a specific provider
97
+ pip install "agex[openai]" # For OpenAI models
98
+ pip install "agex[anthropic]" # For Anthropic Claude models
99
+ pip install "agex[gemini]" # For Google Gemini models
100
+
101
+ # Or install with all providers
102
+ pip install "agex[all-providers]"
103
+ ```
104
+
105
+ ## Project Status
106
+
107
+ > **⚠️ Pre-Release**
108
+ > `agex` is a new framework in active development. While the core concepts are stabilizing, the API should be considered experimental and is subject to change.
109
+
110
+ For teams looking for a more battle-tested library built on the same "agents-that-think-in-code" philosophy, we highly recommend Hugging Face's excellent [`smolagents`](https://github.com/huggingface/smolagents) project. `agex` explores a different architectural path, focusing on deep runtime interoperability and a secure, sandboxed environment for direct integration with existing Python libraries.
111
+
112
+ ## Contributing
113
+
114
+ We welcome contributions! See our [Contributing Guide](CONTRIBUTING.md) for details on our development workflow, code style, and how to submit pull requests. For bug reports and feature requests, please use [GitHub Issues](https://github.com/ashenfad/agex/issues).
agex-0.1.0/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # agex: Library-Friendly Agents
2
+
3
+ **`agex`** (a portmanteau of **age**nt **ex**ecution) is a Python-native agentic framework that enables AI agents to work directly with your existing libraries and codebase.
4
+
5
+ ![agex demo gif](docs/assets/teaser.gif)
6
+
7
+ **This works because** `agex` agents can accept and return complex types like `pandas.DataFrame` and `plotly.Figure` objects without intermediate JSON serialization. For a deeper dive, check out the full **[agex101.ipynb tutorial](https://ashenfad.github.io/agex/examples/agex101/)** or see **[geospatial routing with OSMnx](https://ashenfad.github.io/agex/examples/routing/)** for advanced multi-library integration.
8
+
9
+ ## What Makes This Different
10
+
11
+ `agex` uses a subset of Python as the agent action space, executing actions in a sandboxed environment within your process. This approach avoids the complexity of JSON serialization and allows complex objects to flow directly between your code and the agent. You control exactly what functions, classes, and modules are available, creating a powerful yet secure environment.
12
+
13
+ - **Code-as-Action**: Secure, sandboxed Python execution for agents.
14
+ - **Library Integration**: Use your existing code directly, no tool-making required.
15
+ - **Workspace Persistence**: Git-like versioning for agent state and memory.
16
+ - **Multi-Agent**: Orchestrate agents with natural Python control flow.
17
+ - **Event Streams**: Real-time, notebook-friendly observability.
18
+ - **Benchmarking**: A framework for data-driven agent evaluation.
19
+
20
+ ## Documentation
21
+
22
+ Complete documentation is hosted at **[ashenfad.github.io/agex](https://ashenfad.github.io/agex/)**.
23
+
24
+ Key sections:
25
+ - **[📚 Quick Start Guide](https://ashenfad.github.io/agex/quick-start/)**
26
+ - **[🔭 The Big Picture](https://ashenfad.github.io/agex/concepts/big-picture/)**
27
+ - **[💡 Examples](https://ashenfad.github.io/agex/examples/overview/)**
28
+ - **[📖 API Reference](https://ashenfad.github.io/agex/api/overview/)**
29
+
30
+ ## Installation
31
+
32
+ Install agex with your preferred LLM provider:
33
+
34
+ ```bash
35
+ # Install with a specific provider
36
+ pip install "agex[openai]" # For OpenAI models
37
+ pip install "agex[anthropic]" # For Anthropic Claude models
38
+ pip install "agex[gemini]" # For Google Gemini models
39
+
40
+ # Or install with all providers
41
+ pip install "agex[all-providers]"
42
+ ```
43
+
44
+ ## Project Status
45
+
46
+ > **⚠️ Pre-Release**
47
+ > `agex` is a new framework in active development. While the core concepts are stabilizing, the API should be considered experimental and is subject to change.
48
+
49
+ For teams looking for a more battle-tested library built on the same "agents-that-think-in-code" philosophy, we highly recommend Hugging Face's excellent [`smolagents`](https://github.com/huggingface/smolagents) project. `agex` explores a different architectural path, focusing on deep runtime interoperability and a secure, sandboxed environment for direct integration with existing Python libraries.
50
+
51
+ ## Contributing
52
+
53
+ We welcome contributions! See our [Contributing Guide](CONTRIBUTING.md) for details on our development workflow, code style, and how to submit pull requests. For bug reports and feature requests, please use [GitHub Issues](https://github.com/ashenfad/agex/issues).
@@ -0,0 +1,60 @@
1
+ from .agent import (
2
+ Agent,
3
+ MemberSpec,
4
+ TaskFail,
5
+ clear_agent_registry,
6
+ )
7
+ from .agent.console import pprint_events
8
+ from .agent.datatypes import TaskClarify, TaskTimeout
9
+ from .agent.events import (
10
+ ActionEvent,
11
+ ClarifyEvent,
12
+ ErrorEvent,
13
+ Event,
14
+ FailEvent,
15
+ OutputEvent,
16
+ SuccessEvent,
17
+ TaskStartEvent,
18
+ )
19
+ from .llm import LLMClient, connect_llm
20
+ from .render.view import view
21
+ from .state import Live, Namespaced, Versioned, events
22
+ from .state.kv import Cache, Disk, Memory
23
+
24
+ __all__ = [
25
+ # Core Classes
26
+ "Agent",
27
+ "LLMClient",
28
+ # State Management
29
+ "Versioned",
30
+ "Live",
31
+ "Namespaced",
32
+ "events",
33
+ # Task Control Exceptions & Functions
34
+ "TaskFail",
35
+ "TaskClarify",
36
+ "TaskTimeout",
37
+ # Registration
38
+ "MemberSpec",
39
+ # Events
40
+ "Event",
41
+ "TaskStartEvent",
42
+ "ActionEvent",
43
+ "OutputEvent",
44
+ "SuccessEvent",
45
+ "FailEvent",
46
+ "ClarifyEvent",
47
+ "ErrorEvent",
48
+ # Agent Registry
49
+ "clear_agent_registry",
50
+ # LLM Client Factory
51
+ "connect_llm",
52
+ # View
53
+ "view",
54
+ # KV backends
55
+ "Memory",
56
+ "Disk",
57
+ "Cache",
58
+ # Console
59
+ "pprint_events",
60
+ ]
@@ -0,0 +1,86 @@
1
+ # Main agent functionality
2
+ from ..llm import LLMClient
3
+ from .base import BaseAgent, clear_agent_registry, register_agent, resolve_agent
4
+
5
+ # Data types and exceptions
6
+ from .datatypes import (
7
+ RESERVED_NAMES,
8
+ AttrDescriptor,
9
+ MemberSpec,
10
+ Pattern,
11
+ RegisteredClass,
12
+ RegisteredFn,
13
+ RegisteredItem,
14
+ RegisteredModule,
15
+ TaskContinue,
16
+ TaskFail,
17
+ TaskSuccess,
18
+ Visibility,
19
+ )
20
+ from .loop import TaskLoopMixin
21
+
22
+ # Fingerprinting (usually internal, but exported for testing)
23
+ from .registration import RegistrationMixin
24
+ from .task import TaskMixin, clear_dynamic_dataclass_registry
25
+
26
+ __all__ = [
27
+ # Core functionality
28
+ "register_agent",
29
+ "resolve_agent",
30
+ "clear_agent_registry",
31
+ "clear_dynamic_dataclass_registry",
32
+ # Task control functions
33
+ "TaskSuccess",
34
+ "TaskFail",
35
+ "TaskContinue",
36
+ # Registration types
37
+ "MemberSpec",
38
+ "AttrDescriptor",
39
+ "RegisteredItem",
40
+ "RegisteredFn",
41
+ "RegisteredClass",
42
+ "RegisteredModule",
43
+ # Type aliases and constants
44
+ "Pattern",
45
+ "Visibility",
46
+ "RESERVED_NAMES",
47
+ # Fingerprinting
48
+ ]
49
+
50
+
51
+ class Agent(RegistrationMixin, TaskMixin, TaskLoopMixin, BaseAgent):
52
+ def __init__(
53
+ self,
54
+ primer: str | None = None,
55
+ timeout_seconds: float = 5.0,
56
+ max_iterations: int = 10,
57
+ max_tokens: int = 2**16,
58
+ # Agent identification
59
+ name: str | None = None,
60
+ # LLM configuration (optional, uses smart defaults)
61
+ llm_client: LLMClient | None = None,
62
+ # LLM retry controls
63
+ llm_max_retries: int = 2,
64
+ llm_retry_backoff: float = 0.25,
65
+ ):
66
+ """
67
+ An agent that can be used to execute tasks.
68
+
69
+ Args:
70
+ primer: A string to guide the agent's behavior.
71
+ timeout_seconds: The maximum time in seconds for a single action evaluation.
72
+ max_iterations: The maximum number of think-act cycles for a task.
73
+ max_tokens: The maximum number of tokens to use for context rendering.
74
+ name: Unique identifier for this agent (for sub-agent namespacing).
75
+ llm_client: An instantiated LLMClient for the agent to use.
76
+ """
77
+ super().__init__(
78
+ primer,
79
+ timeout_seconds,
80
+ max_iterations,
81
+ max_tokens,
82
+ name=name,
83
+ llm_client=llm_client,
84
+ llm_max_retries=llm_max_retries,
85
+ llm_retry_backoff=llm_retry_backoff,
86
+ )
@@ -0,0 +1,126 @@
1
+ import uuid
2
+ from typing import Any, Callable, Dict, Literal
3
+
4
+ from ..llm import LLMClient, connect_llm
5
+ from .datatypes import (
6
+ MemberSpec,
7
+ RegisteredClass,
8
+ )
9
+ from .fingerprint import compute_agent_fingerprint_from_policy
10
+ from .policy.policy import AgentPolicy
11
+
12
+ # Global registry mapping fingerprints to agents
13
+ _AGENT_REGISTRY: Dict[str, "BaseAgent"] = {}
14
+ # Global registry mapping agent names to agents
15
+ _AGENT_REGISTRY_BY_NAME: Dict[str, "BaseAgent"] = {}
16
+
17
+
18
+ def register_agent(agent: "BaseAgent") -> str:
19
+ """
20
+ Register an agent in the global registry.
21
+
22
+ Returns the agent's fingerprint.
23
+ """
24
+ # Enforce unique agent names if provided
25
+ if hasattr(agent, "name") and agent.name is not None:
26
+ if agent.name in _AGENT_REGISTRY_BY_NAME:
27
+ existing_agent = _AGENT_REGISTRY_BY_NAME[agent.name]
28
+ if existing_agent is not agent: # Allow re-registration of same agent
29
+ raise ValueError(f"Agent name '{agent.name}' already exists")
30
+ _AGENT_REGISTRY_BY_NAME[agent.name] = agent
31
+
32
+ fingerprint = compute_agent_fingerprint_from_policy(agent)
33
+ _AGENT_REGISTRY[fingerprint] = agent
34
+ return fingerprint
35
+
36
+
37
+ def resolve_agent(fingerprint: str) -> "BaseAgent":
38
+ """
39
+ Resolve an agent by its fingerprint.
40
+
41
+ Raises RuntimeError if no matching agent is found.
42
+ """
43
+ agent = _AGENT_REGISTRY.get(fingerprint)
44
+ if not agent:
45
+ available = list(_AGENT_REGISTRY.keys())
46
+ raise RuntimeError(
47
+ f"No agent found with fingerprint '{fingerprint[:8]}...'. "
48
+ f"Available fingerprints: {[fp[:8] + '...' for fp in available]}"
49
+ )
50
+ return agent
51
+
52
+
53
+ def clear_agent_registry() -> None:
54
+ """Clear the global registry. Primarily for testing."""
55
+ from .task import clear_dynamic_dataclass_registry
56
+
57
+ global _AGENT_REGISTRY, _AGENT_REGISTRY_BY_NAME
58
+ _AGENT_REGISTRY = {}
59
+ _AGENT_REGISTRY_BY_NAME = {}
60
+ clear_dynamic_dataclass_registry()
61
+
62
+
63
+ def _random_name() -> str:
64
+ return f"agent_{uuid.uuid4().hex[:8]}"
65
+
66
+
67
+ class BaseAgent:
68
+ def __init__(
69
+ self,
70
+ primer: str | None,
71
+ timeout_seconds: float,
72
+ max_iterations: int,
73
+ max_tokens: int,
74
+ # Agent identification
75
+ name: str | None = None,
76
+ # LLM configuration (optional, uses smart defaults)
77
+ llm_client: LLMClient | None = None,
78
+ # LLM retry controls
79
+ llm_max_retries: int = 2,
80
+ llm_retry_backoff: float = 0.25,
81
+ ):
82
+ self.name = name or _random_name()
83
+ self.primer = primer
84
+ self.timeout_seconds = timeout_seconds
85
+ self.max_iterations = max_iterations
86
+ self.max_tokens = max_tokens
87
+
88
+ # Create LLM client using the resolved configuration
89
+ self.llm_client = llm_client or connect_llm()
90
+ # LLM retry settings
91
+ self.llm_max_retries = llm_max_retries
92
+ self.llm_retry_backoff = llm_retry_backoff
93
+
94
+ # private, host-side registry for live, unpickleable objects
95
+ self._host_object_registry: dict[str, Any] = {}
96
+
97
+ self._policy: AgentPolicy = AgentPolicy()
98
+
99
+ # Auto-register this agent
100
+ self.fingerprint = register_agent(self)
101
+
102
+ def _update_fingerprint(self):
103
+ """Update the fingerprint after registration changes."""
104
+ self.fingerprint = register_agent(self)
105
+
106
+ def module(
107
+ self,
108
+ obj: Any,
109
+ *,
110
+ name: str | None = None,
111
+ visibility: Literal["high", "medium", "low"] = "medium",
112
+ include: list[str] | None = None,
113
+ exclude: list[str] | None = None,
114
+ configure: dict[str, MemberSpec | RegisteredClass] | None = None,
115
+ ) -> None:
116
+ """
117
+ Stub implementation of module registration.
118
+ The full implementation with include/exclude support is in RegistrationMixin.
119
+ This method should not be called directly - use Agent class instead.
120
+ """
121
+ raise NotImplementedError(
122
+ "This is a stub implementation. Use the Agent class which inherits from "
123
+ "RegistrationMixin for full include/exclude support."
124
+ )
125
+
126
+ def task(self, prompt: str | Callable) -> Callable[..., Any]: ...