agentomatic 0.9.0__tar.gz → 1.0.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.
- {agentomatic-0.9.0 → agentomatic-1.0.0}/PKG-INFO +1 -1
- {agentomatic-0.9.0 → agentomatic-1.0.0}/pyproject.toml +3 -1
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/_version.py +1 -1
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/optimizers.py +6 -3
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/cli/commands.py +5 -1
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/cli/templates.py +5 -5
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/config/settings.py +10 -4
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/platform.py +23 -21
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/demo/__init__.py +2 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/__init__.py +13 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/failure_analysis.py +5 -2
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/fitter.py +6 -3
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/fitter_optimizers.py +7 -6
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/judges.py +5 -2
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/llm_caller.py +55 -10
- agentomatic-1.0.0/src/agentomatic/optimize/llm_types.py +327 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/loop.py +11 -4
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/metrics.py +54 -65
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/optimizer.py +7 -4
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/strategies.py +33 -56
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/synthesizer.py +15 -29
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/plugins/__init__.py +2 -0
- agentomatic-1.0.0/src/agentomatic/protocols/__init__.py +17 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/providers/__init__.py +2 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/providers/llm.py +128 -14
- agentomatic-1.0.0/src/agentomatic/studio/serve.py +278 -0
- agentomatic-1.0.0/src/agentomatic/studio/static/asset-manifest.json +13 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/static/index.html +1 -1
- agentomatic-1.0.0/src/agentomatic/studio/static/static/css/main.7a2ec864.css +4 -0
- agentomatic-1.0.0/src/agentomatic/studio/static/static/css/main.7a2ec864.css.map +1 -0
- agentomatic-1.0.0/src/agentomatic/studio/static/static/js/main.ea13ebe0.js +3 -0
- agentomatic-1.0.0/src/agentomatic/studio/static/static/js/main.ea13ebe0.js.map +1 -0
- agentomatic-1.0.0/tests/test_llm_types.py +554 -0
- agentomatic-0.9.0/src/agentomatic/protocols/__init__.py +0 -3
- agentomatic-0.9.0/src/agentomatic/studio/serve.py +0 -98
- agentomatic-0.9.0/src/agentomatic/studio/static/asset-manifest.json +0 -13
- agentomatic-0.9.0/src/agentomatic/studio/static/static/css/main.8b3c42dd.css +0 -4
- agentomatic-0.9.0/src/agentomatic/studio/static/static/css/main.8b3c42dd.css.map +0 -1
- agentomatic-0.9.0/src/agentomatic/studio/static/static/js/main.cbb2a8ee.js +0 -3
- agentomatic-0.9.0/src/agentomatic/studio/static/static/js/main.cbb2a8ee.js.map +0 -1
- {agentomatic-0.9.0 → agentomatic-1.0.0}/LICENSE +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/README.md +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/examples/full_agent/README.md +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/base.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/builder.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/decorators.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/graph.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/metrics.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/mixins/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/mixins/dataset.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/mixins/evaluation.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/mixins/graph_execution.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/mixins/observability.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/mixins/optimization.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/mixins/serialization.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/agents/types.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/cli/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/config/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/config/defaults.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/lifespan.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/manifest.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/memory_manager.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/registry.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/router_factory.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/schemas.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/core/state.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/delegation/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/delegation/handoff.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/delegation/swarm.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/demo/agent.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/demo/server.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/middleware/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/middleware/auth.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/middleware/feedback.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/middleware/logging.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/middleware/metrics.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/middleware/rate_limit.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/observability/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/observability/concurrency.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/observability/metrics.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/observability/telemetry.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/config.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/context.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/dashboard.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/dataset.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/deployment.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/eval_contract.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/events.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/progress.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/report.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/runner.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/optimize/search_space.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/builder.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/context.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/engine.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/flow.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/loader.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/models.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/router.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/pipelines/steps.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/plugins/ml.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/plugins/registry.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/plugins/router.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/prompts/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/prompts/manager.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/protocols/decorators.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/providers/embeddings.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/py.typed +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/security/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/security/jwt_auth.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/security/policy.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/security/zero_trust.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/stacks/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/stacks/defaults.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/stacks/manager.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/storage/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/storage/base.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/storage/checkpointer.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/storage/memory.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/storage/models.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/storage/sqlalchemy.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/adapter.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/adapters/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/adapters/generic.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/adapters/graph_agent.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/adapters/langchain.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/adapters/langgraph.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/decorators.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/graph_inspector.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/models.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/router.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/run_tracker.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/static/imgs/graph_view.png +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/static/imgs/logo.png +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/static/imgs/main_screen.png +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/static/imgs/main_screen_ok.png +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/studio/static/manifest.json +0 -0
- /agentomatic-0.9.0/src/agentomatic/studio/static/static/js/main.cbb2a8ee.js.LICENSE.txt → /agentomatic-1.0.0/src/agentomatic/studio/static/static/js/main.ea13ebe0.js.LICENSE.txt +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/ui/__init__.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/src/agentomatic/ui/chat.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_agent_dataset.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_agent_graph.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_agent_graph_stream.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_agent_metrics.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_agentomatic.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_base_graph_agent.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_bugfixes_041.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_cli.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_coverage_boost.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_deep_agent.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_delegation.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_fitter.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_flow.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_integration.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_optimize.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_optimizer_dashboard.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_optimizer_events.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_optimizer_progress.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_pipelines.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_platform_features.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_plugins.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_security.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_stacks.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_studio.py +0 -0
- {agentomatic-0.9.0 → agentomatic-1.0.0}/tests/test_v06_core.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentomatic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Drop agents, not code — zero-code multi-agent API platform framework
|
|
5
5
|
Project-URL: Homepage, https://github.com/UnicoLab/agentomatic
|
|
6
6
|
Project-URL: Documentation, https://unicolab.github.io/agentomatic
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agentomatic"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "1.0.0"
|
|
4
4
|
description = "Drop agents, not code — zero-code multi-agent API platform framework"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "MIT"}
|
|
@@ -92,6 +92,8 @@ Changelog = "https://github.com/UnicoLab/agentomatic/blob/main/CHANGELOG.md"
|
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
|
|
95
|
+
|
|
96
|
+
|
|
95
97
|
[dependency-groups]
|
|
96
98
|
dev = [
|
|
97
99
|
"pytest>=8",
|
|
@@ -12,12 +12,15 @@ from __future__ import annotations
|
|
|
12
12
|
|
|
13
13
|
import itertools
|
|
14
14
|
from collections.abc import Sequence
|
|
15
|
-
from typing import Any
|
|
15
|
+
from typing import TYPE_CHECKING, Any
|
|
16
16
|
|
|
17
17
|
from loguru import logger
|
|
18
18
|
|
|
19
19
|
from .types import AgentDataset, Metric
|
|
20
20
|
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from agentomatic.optimize.llm_types import LLMSpec
|
|
23
|
+
|
|
21
24
|
# ---------------------------------------------------------------------------
|
|
22
25
|
# NoOpOptimizer
|
|
23
26
|
# ---------------------------------------------------------------------------
|
|
@@ -175,8 +178,8 @@ class PromptFitterBridge:
|
|
|
175
178
|
def __init__(
|
|
176
179
|
self,
|
|
177
180
|
agent_name: str = "",
|
|
178
|
-
task_model:
|
|
179
|
-
rewrite_model:
|
|
181
|
+
task_model: LLMSpec = "ollama/qwen2.5:7b",
|
|
182
|
+
rewrite_model: LLMSpec = "openai/gpt-4.1",
|
|
180
183
|
**kwargs: Any,
|
|
181
184
|
) -> None:
|
|
182
185
|
self.agent_name = agent_name
|
|
@@ -364,7 +364,11 @@ def init(name: str, agents_dir: str, template: str | None, force: bool) -> None:
|
|
|
364
364
|
@click.option("--title", default=None, help="Platform title")
|
|
365
365
|
@click.option("--log-level", default="INFO", help="Log level")
|
|
366
366
|
@click.option("--with-ui", "--ui", is_flag=True, help="Enable Chainlit debug UI at /chat")
|
|
367
|
-
@click.option(
|
|
367
|
+
@click.option(
|
|
368
|
+
"--studio/--no-studio",
|
|
369
|
+
default=True,
|
|
370
|
+
help="Enable Agentomatic Studio debug UI at /studio/ui (default: on)",
|
|
371
|
+
)
|
|
368
372
|
def run(
|
|
369
373
|
agents_dir: str,
|
|
370
374
|
plugins_dir: str,
|
|
@@ -1720,14 +1720,14 @@ def get_template_files(template: str, name: str) -> dict[str, str]:
|
|
|
1720
1720
|
|
|
1721
1721
|
if template == "basic":
|
|
1722
1722
|
return {
|
|
1723
|
-
"__init__.py": '"""Agent package."""
|
|
1723
|
+
"__init__.py": '"""Agent package."""\n',
|
|
1724
1724
|
"agent.py": _class_agent_py(name, "basic"),
|
|
1725
1725
|
**common,
|
|
1726
1726
|
}
|
|
1727
1727
|
|
|
1728
1728
|
elif template == "full":
|
|
1729
1729
|
return {
|
|
1730
|
-
"__init__.py": '"""Agent package."""
|
|
1730
|
+
"__init__.py": '"""Agent package."""\n',
|
|
1731
1731
|
"agent.py": _class_agent_py(name, "full"),
|
|
1732
1732
|
"config.py": _config_py(name),
|
|
1733
1733
|
"schemas.py": _schemas_py(name),
|
|
@@ -1744,7 +1744,7 @@ def get_template_files(template: str, name: str) -> dict[str, str]:
|
|
|
1744
1744
|
|
|
1745
1745
|
elif template == "coordinator":
|
|
1746
1746
|
return {
|
|
1747
|
-
"__init__.py": '"""Agent package."""
|
|
1747
|
+
"__init__.py": '"""Agent package."""\n',
|
|
1748
1748
|
"agent.py": _coordinator_agent_py(name),
|
|
1749
1749
|
"delegation.py": _coordinator_delegation_py(name),
|
|
1750
1750
|
"security.py": _coordinator_security_py(name),
|
|
@@ -1765,7 +1765,7 @@ def get_template_files(template: str, name: str) -> dict[str, str]:
|
|
|
1765
1765
|
|
|
1766
1766
|
elif template == "rag":
|
|
1767
1767
|
return {
|
|
1768
|
-
"__init__.py": '"""Agent package."""
|
|
1768
|
+
"__init__.py": '"""Agent package."""\n',
|
|
1769
1769
|
"agent.py": _class_agent_py(name, "rag"),
|
|
1770
1770
|
"config.py": _config_py(name),
|
|
1771
1771
|
"tools.py": _tools_py(name),
|
|
@@ -1774,7 +1774,7 @@ def get_template_files(template: str, name: str) -> dict[str, str]:
|
|
|
1774
1774
|
|
|
1775
1775
|
elif template == "chatbot":
|
|
1776
1776
|
return {
|
|
1777
|
-
"__init__.py": '"""Agent package."""
|
|
1777
|
+
"__init__.py": '"""Agent package."""\n',
|
|
1778
1778
|
"agent.py": _class_agent_py(name, "chatbot"),
|
|
1779
1779
|
"config.py": _config_py(name),
|
|
1780
1780
|
**common,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import threading
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Any
|
|
7
8
|
|
|
@@ -105,20 +106,25 @@ class PlatformSettings(BaseSettings):
|
|
|
105
106
|
|
|
106
107
|
|
|
107
108
|
_settings: PlatformSettings | None = None
|
|
109
|
+
_settings_lock = threading.Lock()
|
|
108
110
|
|
|
109
111
|
|
|
110
112
|
def get_settings() -> PlatformSettings:
|
|
111
113
|
"""Get or create the singleton settings instance."""
|
|
112
114
|
global _settings
|
|
113
|
-
if _settings is None:
|
|
114
|
-
_settings
|
|
115
|
-
|
|
115
|
+
if _settings is not None:
|
|
116
|
+
return _settings
|
|
117
|
+
with _settings_lock:
|
|
118
|
+
if _settings is None:
|
|
119
|
+
_settings = PlatformSettings() # type: ignore[call-arg]
|
|
120
|
+
return _settings
|
|
116
121
|
|
|
117
122
|
|
|
118
123
|
def reset_settings() -> None:
|
|
119
124
|
"""Reset settings singleton (for testing)."""
|
|
120
125
|
global _settings
|
|
121
|
-
|
|
126
|
+
with _settings_lock:
|
|
127
|
+
_settings = None
|
|
122
128
|
|
|
123
129
|
|
|
124
130
|
def load_environment(env_file: str | Path | None = None) -> None:
|
|
@@ -790,29 +790,31 @@ class AgentPlatform:
|
|
|
790
790
|
app.include_router(studio_router)
|
|
791
791
|
logger.info("🎨 Studio API mounted at /studio/")
|
|
792
792
|
|
|
793
|
-
# Mount the built Studio UI (
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
logger.info("🎨 Studio UI + redirects mounted")
|
|
808
|
-
else:
|
|
809
|
-
logger.info(
|
|
810
|
-
"🎨 Studio API is running but UI assets not bundled. "
|
|
811
|
-
"Run the frontend separately or build with: "
|
|
812
|
-
"./scripts/build_studio.sh"
|
|
813
|
-
)
|
|
793
|
+
# Mount the built Studio UI (always — shows helpful
|
|
794
|
+
# error page if assets are missing)
|
|
795
|
+
from agentomatic.studio.serve import mount_studio_ui
|
|
796
|
+
|
|
797
|
+
mount_studio_ui(app)
|
|
798
|
+
|
|
799
|
+
# Convenience redirects: /studio → /studio/ui/
|
|
800
|
+
from fastapi.responses import RedirectResponse
|
|
801
|
+
|
|
802
|
+
@app.get("/studio", include_in_schema=False)
|
|
803
|
+
@app.get("/studio/", include_in_schema=False)
|
|
804
|
+
async def _studio_redirect() -> RedirectResponse:
|
|
805
|
+
return RedirectResponse(url="/studio/ui/")
|
|
806
|
+
|
|
814
807
|
except Exception as exc: # noqa: BLE001
|
|
815
808
|
logger.warning(f"Studio setup failed: {exc}")
|
|
809
|
+
else:
|
|
810
|
+
# Studio disabled — mount informative error pages so users
|
|
811
|
+
# hitting /studio/ui/ get guidance instead of a bare 404.
|
|
812
|
+
try:
|
|
813
|
+
from agentomatic.studio.serve import mount_studio_disabled_page
|
|
814
|
+
|
|
815
|
+
mount_studio_disabled_page(app)
|
|
816
|
+
except Exception: # noqa: BLE001
|
|
817
|
+
pass # Non-critical — don't log noise
|
|
816
818
|
|
|
817
819
|
self._app = app
|
|
818
820
|
return app
|
|
@@ -67,6 +67,14 @@ from agentomatic.optimize.judges import (
|
|
|
67
67
|
LocalJudgeMetric,
|
|
68
68
|
MultiJudgePanel,
|
|
69
69
|
)
|
|
70
|
+
|
|
71
|
+
# ── Pluggable LLM type system ────────────────────────────────────────
|
|
72
|
+
from agentomatic.optimize.llm_types import (
|
|
73
|
+
LLMCallable,
|
|
74
|
+
LLMSpec,
|
|
75
|
+
call_llm,
|
|
76
|
+
call_llm_json,
|
|
77
|
+
)
|
|
70
78
|
from agentomatic.optimize.loop import (
|
|
71
79
|
AVAILABLE_STRATEGIES,
|
|
72
80
|
LoopResult,
|
|
@@ -112,6 +120,11 @@ from agentomatic.optimize.synthesizer import (
|
|
|
112
120
|
)
|
|
113
121
|
|
|
114
122
|
__all__ = [
|
|
123
|
+
# ── Pluggable LLM type system ─────────────────────────────────
|
|
124
|
+
"LLMSpec",
|
|
125
|
+
"LLMCallable",
|
|
126
|
+
"call_llm",
|
|
127
|
+
"call_llm_json",
|
|
115
128
|
# Core — local-first optimization loop
|
|
116
129
|
"PromptOptimizationLoop",
|
|
117
130
|
"LoopResult",
|
|
@@ -13,10 +13,13 @@ Classes
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
from dataclasses import dataclass, field
|
|
16
|
-
from typing import Any
|
|
16
|
+
from typing import TYPE_CHECKING, Any
|
|
17
17
|
|
|
18
18
|
from loguru import logger
|
|
19
19
|
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from agentomatic.optimize.llm_types import LLMSpec
|
|
22
|
+
|
|
20
23
|
# =====================================================================
|
|
21
24
|
# Failure Clustering
|
|
22
25
|
# =====================================================================
|
|
@@ -71,7 +74,7 @@ class FailureClusterer:
|
|
|
71
74
|
|
|
72
75
|
def __init__(
|
|
73
76
|
self,
|
|
74
|
-
model:
|
|
77
|
+
model: LLMSpec = "ollama/qwen2.5:7b",
|
|
75
78
|
max_clusters: int = 8,
|
|
76
79
|
max_examples_per_cluster: int = 3,
|
|
77
80
|
) -> None:
|
|
@@ -43,7 +43,7 @@ import json
|
|
|
43
43
|
import time
|
|
44
44
|
import uuid
|
|
45
45
|
from pathlib import Path
|
|
46
|
-
from typing import Any
|
|
46
|
+
from typing import TYPE_CHECKING, Any
|
|
47
47
|
|
|
48
48
|
from loguru import logger
|
|
49
49
|
|
|
@@ -77,6 +77,9 @@ from agentomatic.optimize.metrics import (
|
|
|
77
77
|
from agentomatic.optimize.runner import AgentRunner, RunResult
|
|
78
78
|
from agentomatic.optimize.search_space import PromptSearchSpace
|
|
79
79
|
|
|
80
|
+
if TYPE_CHECKING:
|
|
81
|
+
from agentomatic.optimize.llm_types import LLMSpec
|
|
82
|
+
|
|
80
83
|
# ---------------------------------------------------------------------------
|
|
81
84
|
# Constants
|
|
82
85
|
# ---------------------------------------------------------------------------
|
|
@@ -164,8 +167,8 @@ class PromptFitter:
|
|
|
164
167
|
self,
|
|
165
168
|
agent: str,
|
|
166
169
|
base_prompt_version: str = "v1",
|
|
167
|
-
task_model:
|
|
168
|
-
rewrite_model:
|
|
170
|
+
task_model: LLMSpec = "ollama/qwen2.5:7b",
|
|
171
|
+
rewrite_model: LLMSpec | None = None,
|
|
169
172
|
local_judges: list[str] | None = None,
|
|
170
173
|
search_space: PromptSearchSpace | None = None,
|
|
171
174
|
optimizer: str | Any = "gepa_like",
|
|
@@ -51,6 +51,7 @@ from agentomatic.optimize.search_space import PromptSearchSpace
|
|
|
51
51
|
|
|
52
52
|
if TYPE_CHECKING:
|
|
53
53
|
from agentomatic.optimize.context import OptimizationContext
|
|
54
|
+
from agentomatic.optimize.llm_types import LLMSpec
|
|
54
55
|
|
|
55
56
|
# =====================================================================
|
|
56
57
|
# Perspectives used by MIPRO-like instruction generation
|
|
@@ -177,7 +178,7 @@ class RewriteOptimizer(BaseFitterOptimizer):
|
|
|
177
178
|
"""
|
|
178
179
|
|
|
179
180
|
name: str = "rewrite"
|
|
180
|
-
model:
|
|
181
|
+
model: LLMSpec = "ollama/qwen2.5:7b"
|
|
181
182
|
max_failures: int = 5
|
|
182
183
|
|
|
183
184
|
async def propose(
|
|
@@ -557,7 +558,7 @@ class MIPROLikeOptimizer(BaseFitterOptimizer):
|
|
|
557
558
|
"""
|
|
558
559
|
|
|
559
560
|
name: str = "mipro_like"
|
|
560
|
-
model:
|
|
561
|
+
model: LLMSpec = "ollama/qwen2.5:7b"
|
|
561
562
|
n_instruction_candidates: int = 5
|
|
562
563
|
n_few_shot_candidates: int = 3
|
|
563
564
|
fuse_top_k: int = 2
|
|
@@ -858,8 +859,8 @@ class GEPALikeOptimizer(BaseFitterOptimizer):
|
|
|
858
859
|
"""
|
|
859
860
|
|
|
860
861
|
name: str = "gepa_like"
|
|
861
|
-
judge_model:
|
|
862
|
-
rewrite_model:
|
|
862
|
+
judge_model: LLMSpec = "ollama/qwen2.5:7b"
|
|
863
|
+
rewrite_model: LLMSpec = "ollama/qwen2.5:7b"
|
|
863
864
|
n_mutations: int = 3
|
|
864
865
|
|
|
865
866
|
# Default mutation aspects when fewer categories are found in feedback
|
|
@@ -1444,8 +1445,8 @@ def _build_failure_summary(
|
|
|
1444
1445
|
|
|
1445
1446
|
def resolve_fitter_optimizer(
|
|
1446
1447
|
name: str | BaseFitterOptimizer,
|
|
1447
|
-
model:
|
|
1448
|
-
rewrite_model:
|
|
1448
|
+
model: LLMSpec = "ollama/qwen2.5:7b",
|
|
1449
|
+
rewrite_model: LLMSpec | None = None,
|
|
1449
1450
|
**kwargs: Any,
|
|
1450
1451
|
) -> BaseFitterOptimizer:
|
|
1451
1452
|
"""Resolve a fitter optimizer by name or pass through an existing instance.
|
|
@@ -15,12 +15,15 @@ from __future__ import annotations
|
|
|
15
15
|
|
|
16
16
|
import asyncio
|
|
17
17
|
from dataclasses import dataclass, field
|
|
18
|
-
from typing import Any
|
|
18
|
+
from typing import TYPE_CHECKING, Any
|
|
19
19
|
|
|
20
20
|
from loguru import logger
|
|
21
21
|
|
|
22
22
|
from agentomatic.optimize.metrics import BaseMetric, EvalResult, MetricResult
|
|
23
23
|
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from agentomatic.optimize.llm_types import LLMSpec
|
|
26
|
+
|
|
24
27
|
# =====================================================================
|
|
25
28
|
# Local SLM Judge
|
|
26
29
|
# =====================================================================
|
|
@@ -48,7 +51,7 @@ class LocalJudgeMetric(BaseMetric):
|
|
|
48
51
|
def __init__(
|
|
49
52
|
self,
|
|
50
53
|
name: str = "local_judge",
|
|
51
|
-
model:
|
|
54
|
+
model: LLMSpec = "ollama/qwen2.5:7b",
|
|
52
55
|
criteria: str = "Evaluate the quality and correctness of the response.",
|
|
53
56
|
dimensions: list[str] | None = None,
|
|
54
57
|
weight: float = 1.0,
|
|
@@ -7,6 +7,8 @@ calling Ollama directly, every call goes through
|
|
|
7
7
|
:class:`LLMCaller` which handles:
|
|
8
8
|
|
|
9
9
|
* **Provider routing** — ``ollama/``, ``openai/``, ``litellm/`` prefixes.
|
|
10
|
+
* **Callable dispatch** — custom async/sync callables and LangChain
|
|
11
|
+
models are transparently supported via :data:`LLMSpec`.
|
|
10
12
|
* **Graceful degradation** — failures are logged and an empty string
|
|
11
13
|
(or empty dict for JSON calls) is returned so the caller never crashes.
|
|
12
14
|
* **JSON extraction** — :meth:`LLMCaller.call_with_json` strips
|
|
@@ -16,16 +18,23 @@ Example
|
|
|
16
18
|
-------
|
|
17
19
|
>>> text = await LLMCaller.call("ollama/mistral:7b", "Say hello")
|
|
18
20
|
>>> data = await LLMCaller.call_with_json("openai/gpt-4o-mini", "Return {\"ok\": true}")
|
|
21
|
+
>>>
|
|
22
|
+
>>> # Custom callable also works:
|
|
23
|
+
>>> async def my_llm(prompt, *, system_prompt=None): return "Hello!"
|
|
24
|
+
>>> text = await LLMCaller.call(my_llm, "Say hello")
|
|
19
25
|
"""
|
|
20
26
|
|
|
21
27
|
from __future__ import annotations
|
|
22
28
|
|
|
23
29
|
import json
|
|
24
30
|
import re
|
|
25
|
-
from typing import Any
|
|
31
|
+
from typing import TYPE_CHECKING, Any
|
|
26
32
|
|
|
27
33
|
from loguru import logger
|
|
28
34
|
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from agentomatic.optimize.llm_types import LLMSpec
|
|
37
|
+
|
|
29
38
|
# =====================================================================
|
|
30
39
|
# Constants
|
|
31
40
|
# =====================================================================
|
|
@@ -102,6 +111,10 @@ class LLMCaller:
|
|
|
102
111
|
|
|
103
112
|
All methods are **static / async** so that no instance state is
|
|
104
113
|
required — just call ``await LLMCaller.call(model, prompt)``.
|
|
114
|
+
|
|
115
|
+
Accepts both **string model specs** (e.g. ``"ollama/mistral:7b"``) and
|
|
116
|
+
**custom callables** (async functions, LangChain models, etc.) via the
|
|
117
|
+
:data:`~agentomatic.optimize.llm_types.LLMSpec` union type.
|
|
105
118
|
"""
|
|
106
119
|
|
|
107
120
|
# -----------------------------------------------------------------
|
|
@@ -110,7 +123,7 @@ class LLMCaller:
|
|
|
110
123
|
|
|
111
124
|
@staticmethod
|
|
112
125
|
async def call(
|
|
113
|
-
model:
|
|
126
|
+
model: LLMSpec,
|
|
114
127
|
prompt: str,
|
|
115
128
|
*,
|
|
116
129
|
system_prompt: str | None = None,
|
|
@@ -124,8 +137,8 @@ class LLMCaller:
|
|
|
124
137
|
Parameters
|
|
125
138
|
----------
|
|
126
139
|
model:
|
|
127
|
-
Model specification
|
|
128
|
-
|
|
140
|
+
Model specification — a string like ``"ollama/mistral:7b"``
|
|
141
|
+
or a callable / LangChain model matching :data:`LLMSpec`.
|
|
129
142
|
prompt:
|
|
130
143
|
User prompt text.
|
|
131
144
|
system_prompt:
|
|
@@ -145,6 +158,21 @@ class LLMCaller:
|
|
|
145
158
|
str
|
|
146
159
|
Generated text, or ``""`` on failure.
|
|
147
160
|
"""
|
|
161
|
+
# ── Non-string: delegate to unified callable dispatcher ──
|
|
162
|
+
if not isinstance(model, str):
|
|
163
|
+
from agentomatic.optimize.llm_types import call_llm
|
|
164
|
+
|
|
165
|
+
return await call_llm(
|
|
166
|
+
model,
|
|
167
|
+
prompt,
|
|
168
|
+
system_prompt=system_prompt,
|
|
169
|
+
temperature=temperature,
|
|
170
|
+
max_tokens=max_tokens,
|
|
171
|
+
json_mode=json_mode,
|
|
172
|
+
timeout=timeout,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# ── String: route to provider backend ────────────────────
|
|
148
176
|
provider, model_name = parse_model_spec(model)
|
|
149
177
|
try:
|
|
150
178
|
if provider == "ollama":
|
|
@@ -196,7 +224,7 @@ class LLMCaller:
|
|
|
196
224
|
|
|
197
225
|
@staticmethod
|
|
198
226
|
async def call_with_json(
|
|
199
|
-
model:
|
|
227
|
+
model: LLMSpec,
|
|
200
228
|
prompt: str,
|
|
201
229
|
*,
|
|
202
230
|
system_prompt: str | None = None,
|
|
@@ -210,10 +238,12 @@ class LLMCaller:
|
|
|
210
238
|
If the first attempt fails to parse, the call is retried up to
|
|
211
239
|
*max_retries* times. Returns an empty ``{}`` on total failure.
|
|
212
240
|
|
|
241
|
+
Accepts both string model specs and callables via :data:`LLMSpec`.
|
|
242
|
+
|
|
213
243
|
Parameters
|
|
214
244
|
----------
|
|
215
245
|
model:
|
|
216
|
-
Model specification (see :meth:`call`).
|
|
246
|
+
Model specification — string or callable (see :meth:`call`).
|
|
217
247
|
prompt:
|
|
218
248
|
User prompt — a JSON-return instruction is appended automatically.
|
|
219
249
|
system_prompt:
|
|
@@ -230,9 +260,23 @@ class LLMCaller:
|
|
|
230
260
|
dict[str, Any]
|
|
231
261
|
Parsed JSON object, or ``{}`` on failure.
|
|
232
262
|
"""
|
|
263
|
+
# For non-string models, delegate to call_llm_json
|
|
264
|
+
if not isinstance(model, str):
|
|
265
|
+
from agentomatic.optimize.llm_types import call_llm_json
|
|
266
|
+
|
|
267
|
+
return await call_llm_json(
|
|
268
|
+
model,
|
|
269
|
+
prompt,
|
|
270
|
+
system_prompt=system_prompt,
|
|
271
|
+
temperature=temperature,
|
|
272
|
+
max_retries=max_retries,
|
|
273
|
+
timeout=timeout,
|
|
274
|
+
)
|
|
275
|
+
|
|
233
276
|
json_instruction = (
|
|
234
277
|
"\n\nIMPORTANT: Reply with ONLY a valid JSON object. "
|
|
235
|
-
"Do not include any other text, explanation, or
|
|
278
|
+
"Do not include any other text, explanation, or "
|
|
279
|
+
"markdown formatting."
|
|
236
280
|
)
|
|
237
281
|
augmented_prompt = prompt + json_instruction
|
|
238
282
|
|
|
@@ -329,9 +373,10 @@ async def _call_openai(
|
|
|
329
373
|
kwargs["response_format"] = {"type": "json_object"}
|
|
330
374
|
|
|
331
375
|
client = openai.AsyncOpenAI(timeout=timeout)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
376
|
+
async with client as c:
|
|
377
|
+
response = await c.chat.completions.create(**kwargs)
|
|
378
|
+
choice = response.choices[0]
|
|
379
|
+
return (choice.message.content or "").strip()
|
|
335
380
|
|
|
336
381
|
|
|
337
382
|
async def _call_litellm(
|