tactus 0.31.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.
- tactus/__init__.py +49 -0
- tactus/adapters/__init__.py +9 -0
- tactus/adapters/broker_log.py +76 -0
- tactus/adapters/cli_hitl.py +189 -0
- tactus/adapters/cli_log.py +223 -0
- tactus/adapters/cost_collector_log.py +56 -0
- tactus/adapters/file_storage.py +367 -0
- tactus/adapters/http_callback_log.py +109 -0
- tactus/adapters/ide_log.py +71 -0
- tactus/adapters/lua_tools.py +336 -0
- tactus/adapters/mcp.py +289 -0
- tactus/adapters/mcp_manager.py +196 -0
- tactus/adapters/memory.py +53 -0
- tactus/adapters/plugins.py +419 -0
- tactus/backends/http_backend.py +58 -0
- tactus/backends/model_backend.py +35 -0
- tactus/backends/pytorch_backend.py +110 -0
- tactus/broker/__init__.py +12 -0
- tactus/broker/client.py +247 -0
- tactus/broker/protocol.py +183 -0
- tactus/broker/server.py +1123 -0
- tactus/broker/stdio.py +12 -0
- tactus/cli/__init__.py +7 -0
- tactus/cli/app.py +2245 -0
- tactus/cli/commands/__init__.py +0 -0
- tactus/core/__init__.py +32 -0
- tactus/core/config_manager.py +790 -0
- tactus/core/dependencies/__init__.py +14 -0
- tactus/core/dependencies/registry.py +180 -0
- tactus/core/dsl_stubs.py +2117 -0
- tactus/core/exceptions.py +66 -0
- tactus/core/execution_context.py +480 -0
- tactus/core/lua_sandbox.py +508 -0
- tactus/core/message_history_manager.py +236 -0
- tactus/core/mocking.py +286 -0
- tactus/core/output_validator.py +291 -0
- tactus/core/registry.py +499 -0
- tactus/core/runtime.py +2907 -0
- tactus/core/template_resolver.py +142 -0
- tactus/core/yaml_parser.py +301 -0
- tactus/docker/Dockerfile +61 -0
- tactus/docker/entrypoint.sh +69 -0
- tactus/dspy/__init__.py +39 -0
- tactus/dspy/agent.py +1144 -0
- tactus/dspy/broker_lm.py +181 -0
- tactus/dspy/config.py +212 -0
- tactus/dspy/history.py +196 -0
- tactus/dspy/module.py +405 -0
- tactus/dspy/prediction.py +318 -0
- tactus/dspy/signature.py +185 -0
- tactus/formatting/__init__.py +7 -0
- tactus/formatting/formatter.py +437 -0
- tactus/ide/__init__.py +9 -0
- tactus/ide/coding_assistant.py +343 -0
- tactus/ide/server.py +2223 -0
- tactus/primitives/__init__.py +49 -0
- tactus/primitives/control.py +168 -0
- tactus/primitives/file.py +229 -0
- tactus/primitives/handles.py +378 -0
- tactus/primitives/host.py +94 -0
- tactus/primitives/human.py +342 -0
- tactus/primitives/json.py +189 -0
- tactus/primitives/log.py +187 -0
- tactus/primitives/message_history.py +157 -0
- tactus/primitives/model.py +163 -0
- tactus/primitives/procedure.py +564 -0
- tactus/primitives/procedure_callable.py +318 -0
- tactus/primitives/retry.py +155 -0
- tactus/primitives/session.py +152 -0
- tactus/primitives/state.py +182 -0
- tactus/primitives/step.py +209 -0
- tactus/primitives/system.py +93 -0
- tactus/primitives/tool.py +375 -0
- tactus/primitives/tool_handle.py +279 -0
- tactus/primitives/toolset.py +229 -0
- tactus/protocols/__init__.py +38 -0
- tactus/protocols/chat_recorder.py +81 -0
- tactus/protocols/config.py +97 -0
- tactus/protocols/cost.py +31 -0
- tactus/protocols/hitl.py +71 -0
- tactus/protocols/log_handler.py +27 -0
- tactus/protocols/models.py +355 -0
- tactus/protocols/result.py +33 -0
- tactus/protocols/storage.py +90 -0
- tactus/providers/__init__.py +13 -0
- tactus/providers/base.py +92 -0
- tactus/providers/bedrock.py +117 -0
- tactus/providers/google.py +105 -0
- tactus/providers/openai.py +98 -0
- tactus/sandbox/__init__.py +63 -0
- tactus/sandbox/config.py +171 -0
- tactus/sandbox/container_runner.py +1099 -0
- tactus/sandbox/docker_manager.py +433 -0
- tactus/sandbox/entrypoint.py +227 -0
- tactus/sandbox/protocol.py +213 -0
- tactus/stdlib/__init__.py +10 -0
- tactus/stdlib/io/__init__.py +13 -0
- tactus/stdlib/io/csv.py +88 -0
- tactus/stdlib/io/excel.py +136 -0
- tactus/stdlib/io/file.py +90 -0
- tactus/stdlib/io/fs.py +154 -0
- tactus/stdlib/io/hdf5.py +121 -0
- tactus/stdlib/io/json.py +109 -0
- tactus/stdlib/io/parquet.py +83 -0
- tactus/stdlib/io/tsv.py +88 -0
- tactus/stdlib/loader.py +274 -0
- tactus/stdlib/tac/tactus/tools/done.tac +33 -0
- tactus/stdlib/tac/tactus/tools/log.tac +50 -0
- tactus/testing/README.md +273 -0
- tactus/testing/__init__.py +61 -0
- tactus/testing/behave_integration.py +380 -0
- tactus/testing/context.py +486 -0
- tactus/testing/eval_models.py +114 -0
- tactus/testing/evaluation_runner.py +222 -0
- tactus/testing/evaluators.py +634 -0
- tactus/testing/events.py +94 -0
- tactus/testing/gherkin_parser.py +134 -0
- tactus/testing/mock_agent.py +315 -0
- tactus/testing/mock_dependencies.py +234 -0
- tactus/testing/mock_hitl.py +171 -0
- tactus/testing/mock_registry.py +168 -0
- tactus/testing/mock_tools.py +133 -0
- tactus/testing/models.py +115 -0
- tactus/testing/pydantic_eval_runner.py +508 -0
- tactus/testing/steps/__init__.py +13 -0
- tactus/testing/steps/builtin.py +902 -0
- tactus/testing/steps/custom.py +69 -0
- tactus/testing/steps/registry.py +68 -0
- tactus/testing/test_runner.py +489 -0
- tactus/tracing/__init__.py +5 -0
- tactus/tracing/trace_manager.py +417 -0
- tactus/utils/__init__.py +1 -0
- tactus/utils/cost_calculator.py +72 -0
- tactus/utils/model_pricing.py +132 -0
- tactus/utils/safe_file_library.py +502 -0
- tactus/utils/safe_libraries.py +234 -0
- tactus/validation/LuaLexerBase.py +66 -0
- tactus/validation/LuaParserBase.py +23 -0
- tactus/validation/README.md +224 -0
- tactus/validation/__init__.py +7 -0
- tactus/validation/error_listener.py +21 -0
- tactus/validation/generated/LuaLexer.interp +231 -0
- tactus/validation/generated/LuaLexer.py +5548 -0
- tactus/validation/generated/LuaLexer.tokens +124 -0
- tactus/validation/generated/LuaLexerBase.py +66 -0
- tactus/validation/generated/LuaParser.interp +173 -0
- tactus/validation/generated/LuaParser.py +6439 -0
- tactus/validation/generated/LuaParser.tokens +124 -0
- tactus/validation/generated/LuaParserBase.py +23 -0
- tactus/validation/generated/LuaParserVisitor.py +118 -0
- tactus/validation/generated/__init__.py +7 -0
- tactus/validation/grammar/LuaLexer.g4 +123 -0
- tactus/validation/grammar/LuaParser.g4 +178 -0
- tactus/validation/semantic_visitor.py +817 -0
- tactus/validation/validator.py +157 -0
- tactus-0.31.0.dist-info/METADATA +1809 -0
- tactus-0.31.0.dist-info/RECORD +160 -0
- tactus-0.31.0.dist-info/WHEEL +4 -0
- tactus-0.31.0.dist-info/entry_points.txt +2 -0
- tactus-0.31.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dependency injection infrastructure for Tactus procedures.
|
|
3
|
+
|
|
4
|
+
This package provides the infrastructure for declaring, creating, and managing
|
|
5
|
+
external dependencies like HTTP clients, databases, and caches.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .registry import ResourceType, ResourceFactory, ResourceManager
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"ResourceType",
|
|
12
|
+
"ResourceFactory",
|
|
13
|
+
"ResourceManager",
|
|
14
|
+
]
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Resource registry for dependency injection in Tactus procedures.
|
|
3
|
+
|
|
4
|
+
This module provides the infrastructure for declaring, creating, and managing
|
|
5
|
+
external dependencies (HTTP clients, databases, caches) that procedures need.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import Dict, Any
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ResourceType(Enum):
|
|
16
|
+
"""Supported dependency resource types."""
|
|
17
|
+
|
|
18
|
+
HTTP_CLIENT = "http_client"
|
|
19
|
+
POSTGRES = "postgres"
|
|
20
|
+
REDIS = "redis"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ResourceFactory:
|
|
24
|
+
"""
|
|
25
|
+
Factory for creating real dependency resources from configuration.
|
|
26
|
+
|
|
27
|
+
This factory creates actual HTTP clients, database connections, etc.
|
|
28
|
+
based on the configuration provided in procedure DSL.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
async def create(resource_type: str, config: Dict[str, Any]) -> Any:
|
|
33
|
+
"""
|
|
34
|
+
Create a real resource from configuration.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
resource_type: Type of resource (http_client, postgres, redis)
|
|
38
|
+
config: Configuration dictionary from procedure DSL
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Configured resource instance
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
ValueError: If resource_type is unknown
|
|
45
|
+
ImportError: If required library is not installed
|
|
46
|
+
"""
|
|
47
|
+
if resource_type == ResourceType.HTTP_CLIENT.value:
|
|
48
|
+
return await ResourceFactory._create_http_client(config)
|
|
49
|
+
elif resource_type == ResourceType.POSTGRES.value:
|
|
50
|
+
return await ResourceFactory._create_postgres(config)
|
|
51
|
+
elif resource_type == ResourceType.REDIS.value:
|
|
52
|
+
return await ResourceFactory._create_redis(config)
|
|
53
|
+
else:
|
|
54
|
+
raise ValueError(f"Unknown resource type: {resource_type}")
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
async def _create_http_client(config: Dict[str, Any]) -> Any:
|
|
58
|
+
"""Create HTTP client (httpx.AsyncClient)."""
|
|
59
|
+
try:
|
|
60
|
+
import httpx
|
|
61
|
+
except ImportError:
|
|
62
|
+
raise ImportError(
|
|
63
|
+
"httpx is required for HTTP client dependencies. Install it with: pip install httpx"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
base_url = config.get("base_url")
|
|
67
|
+
headers = config.get("headers", {})
|
|
68
|
+
timeout = config.get("timeout", 30.0)
|
|
69
|
+
|
|
70
|
+
logger.info(f"Creating HTTP client for base_url={base_url}")
|
|
71
|
+
|
|
72
|
+
return httpx.AsyncClient(base_url=base_url, headers=headers, timeout=timeout)
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
async def _create_postgres(config: Dict[str, Any]) -> Any:
|
|
76
|
+
"""Create PostgreSQL connection pool (asyncpg.Pool)."""
|
|
77
|
+
try:
|
|
78
|
+
import asyncpg
|
|
79
|
+
except ImportError:
|
|
80
|
+
raise ImportError(
|
|
81
|
+
"asyncpg is required for PostgreSQL dependencies. "
|
|
82
|
+
"Install it with: pip install asyncpg"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
connection_string = config["connection_string"]
|
|
86
|
+
pool_size = config.get("pool_size", 10)
|
|
87
|
+
max_pool_size = config.get("max_pool_size", 20)
|
|
88
|
+
|
|
89
|
+
logger.info(f"Creating PostgreSQL pool with size={pool_size}")
|
|
90
|
+
|
|
91
|
+
return await asyncpg.create_pool(
|
|
92
|
+
connection_string, min_size=pool_size, max_size=max_pool_size
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
async def _create_redis(config: Dict[str, Any]) -> Any:
|
|
97
|
+
"""Create Redis client (redis.asyncio.Redis)."""
|
|
98
|
+
try:
|
|
99
|
+
import redis.asyncio as redis
|
|
100
|
+
except ImportError:
|
|
101
|
+
raise ImportError(
|
|
102
|
+
"redis is required for Redis dependencies. Install it with: pip install redis"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
url = config["url"]
|
|
106
|
+
|
|
107
|
+
logger.info(f"Creating Redis client for url={url}")
|
|
108
|
+
|
|
109
|
+
return redis.from_url(url, encoding="utf-8", decode_responses=True)
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
async def create_all(dependencies_config: Dict[str, Dict[str, Any]]) -> Dict[str, Any]:
|
|
113
|
+
"""
|
|
114
|
+
Create all dependencies from configuration.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
dependencies_config: Dict mapping dependency name to config
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Dict mapping dependency name to created resource
|
|
121
|
+
"""
|
|
122
|
+
resources = {}
|
|
123
|
+
|
|
124
|
+
for name, config in dependencies_config.items():
|
|
125
|
+
resource_type = config.get("type")
|
|
126
|
+
if not resource_type:
|
|
127
|
+
raise ValueError(f"Dependency '{name}' missing 'type' field")
|
|
128
|
+
|
|
129
|
+
logger.info(f"Creating dependency '{name}' of type '{resource_type}'")
|
|
130
|
+
resources[name] = await ResourceFactory.create(resource_type, config)
|
|
131
|
+
|
|
132
|
+
return resources
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class ResourceManager:
|
|
136
|
+
"""
|
|
137
|
+
Manages lifecycle of dependency resources.
|
|
138
|
+
|
|
139
|
+
Handles cleanup of HTTP connections, database pools, etc.
|
|
140
|
+
when procedure completes.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def __init__(self):
|
|
144
|
+
self.resources: Dict[str, Any] = {}
|
|
145
|
+
|
|
146
|
+
async def add_resource(self, name: str, resource: Any) -> None:
|
|
147
|
+
"""Add a resource to be managed."""
|
|
148
|
+
self.resources[name] = resource
|
|
149
|
+
logger.debug(f"Added resource '{name}' to manager")
|
|
150
|
+
|
|
151
|
+
async def cleanup(self) -> None:
|
|
152
|
+
"""Clean up all managed resources."""
|
|
153
|
+
logger.info(f"Cleaning up {len(self.resources)} resources")
|
|
154
|
+
|
|
155
|
+
for name, resource in self.resources.items():
|
|
156
|
+
try:
|
|
157
|
+
await self._cleanup_resource(name, resource)
|
|
158
|
+
except Exception as e:
|
|
159
|
+
logger.error(f"Error cleaning up resource '{name}': {e}")
|
|
160
|
+
|
|
161
|
+
async def _cleanup_resource(self, name: str, resource: Any) -> None:
|
|
162
|
+
"""Clean up a single resource based on its type."""
|
|
163
|
+
# HTTP client cleanup
|
|
164
|
+
if hasattr(resource, "aclose"):
|
|
165
|
+
logger.debug(f"Closing HTTP client '{name}'")
|
|
166
|
+
await resource.aclose()
|
|
167
|
+
|
|
168
|
+
# PostgreSQL pool cleanup
|
|
169
|
+
elif hasattr(resource, "close") and hasattr(resource, "wait_closed"):
|
|
170
|
+
logger.debug(f"Closing PostgreSQL pool '{name}'")
|
|
171
|
+
await resource.close()
|
|
172
|
+
await resource.wait_closed()
|
|
173
|
+
|
|
174
|
+
# Redis client cleanup
|
|
175
|
+
elif hasattr(resource, "close") and not hasattr(resource, "wait_closed"):
|
|
176
|
+
logger.debug(f"Closing Redis client '{name}'")
|
|
177
|
+
await resource.close()
|
|
178
|
+
|
|
179
|
+
else:
|
|
180
|
+
logger.warning(f"Unknown resource type for '{name}', no cleanup performed")
|