tactus 0.27.0__py3-none-any.whl → 0.28.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 +1 -1
- tactus/adapters/broker_log.py +25 -4
- tactus/broker/client.py +5 -18
- tactus/broker/protocol.py +183 -0
- tactus/broker/server.py +81 -69
- tactus/cli/app.py +2 -2
- tactus/core/dsl_stubs.py +236 -21
- tactus/core/runtime.py +48 -24
- tactus/docker/entrypoint.sh +3 -2
- tactus/dspy/agent.py +54 -36
- tactus/primitives/tool_handle.py +3 -1
- tactus/sandbox/config.py +23 -7
- tactus/sandbox/container_runner.py +34 -6
- tactus/stdlib/tac/tactus/tools/done.tac +3 -3
- tactus/stdlib/tac/tactus/tools/log.tac +1 -0
- tactus/testing/context.py +0 -1
- tactus/validation/semantic_visitor.py +32 -22
- {tactus-0.27.0.dist-info → tactus-0.28.0.dist-info}/METADATA +118 -15
- {tactus-0.27.0.dist-info → tactus-0.28.0.dist-info}/RECORD +22 -21
- {tactus-0.27.0.dist-info → tactus-0.28.0.dist-info}/WHEEL +0 -0
- {tactus-0.27.0.dist-info → tactus-0.28.0.dist-info}/entry_points.txt +0 -0
- {tactus-0.27.0.dist-info → tactus-0.28.0.dist-info}/licenses/LICENSE +0 -0
tactus/primitives/tool_handle.py
CHANGED
|
@@ -33,6 +33,7 @@ class ToolHandle:
|
|
|
33
33
|
impl_fn: Callable,
|
|
34
34
|
tool_primitive: Optional["ToolPrimitive"] = None,
|
|
35
35
|
is_async: bool = False,
|
|
36
|
+
record_calls: bool = True,
|
|
36
37
|
):
|
|
37
38
|
"""
|
|
38
39
|
Initialize a tool handle.
|
|
@@ -47,6 +48,7 @@ class ToolHandle:
|
|
|
47
48
|
self.impl_fn = impl_fn
|
|
48
49
|
self.tool_primitive = tool_primitive
|
|
49
50
|
self.is_async = is_async
|
|
51
|
+
self.record_calls = record_calls
|
|
50
52
|
|
|
51
53
|
logger.debug(f"ToolHandle created for '{name}' (async={is_async})")
|
|
52
54
|
|
|
@@ -77,7 +79,7 @@ class ToolHandle:
|
|
|
77
79
|
result = self.impl_fn(args)
|
|
78
80
|
|
|
79
81
|
# Record the call for tracking
|
|
80
|
-
if self.tool_primitive:
|
|
82
|
+
if self.tool_primitive and self.record_calls:
|
|
81
83
|
self.tool_primitive.record_call(self.name, args, result)
|
|
82
84
|
|
|
83
85
|
logger.debug(f"ToolHandle.call('{self.name}') returned: {result}")
|
tactus/sandbox/config.py
CHANGED
|
@@ -7,7 +7,7 @@ Defines the SandboxConfig Pydantic model for controlling container execution.
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Dict, List, Optional
|
|
9
9
|
|
|
10
|
-
from pydantic import BaseModel, Field
|
|
10
|
+
from pydantic import BaseModel, Field, model_validator
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class SandboxLimits(BaseModel):
|
|
@@ -52,6 +52,12 @@ class SandboxConfig(BaseModel):
|
|
|
52
52
|
description="Additional environment variables to pass to the container",
|
|
53
53
|
)
|
|
54
54
|
|
|
55
|
+
# Volume mount settings
|
|
56
|
+
mount_current_dir: bool = Field(
|
|
57
|
+
default=True,
|
|
58
|
+
description="Mount current directory to /workspace:rw by default. Set false to disable.",
|
|
59
|
+
)
|
|
60
|
+
|
|
55
61
|
# Additional volume mounts
|
|
56
62
|
volumes: List[str] = Field(
|
|
57
63
|
default_factory=list,
|
|
@@ -60,16 +66,17 @@ class SandboxConfig(BaseModel):
|
|
|
60
66
|
|
|
61
67
|
# Network mode
|
|
62
68
|
network: str = Field(
|
|
63
|
-
default="
|
|
64
|
-
description="Docker network mode (bridge
|
|
69
|
+
default="bridge",
|
|
70
|
+
description="Docker network mode (bridge for broker access, none blocks all network)",
|
|
65
71
|
)
|
|
66
72
|
|
|
67
73
|
# Broker transport (how the secretless runtime reaches the host broker)
|
|
68
|
-
# -
|
|
69
|
-
# -
|
|
74
|
+
# - tcp: Standard mode using TCP sockets (works locally and in K8s/cloud)
|
|
75
|
+
# - tls: TCP with TLS encryption (for production deployments)
|
|
76
|
+
# - stdio: Legacy mode using stdin/stdout (deprecated due to buffering issues)
|
|
70
77
|
broker_transport: str = Field(
|
|
71
|
-
default="
|
|
72
|
-
description="Broker transport for the runtime container:
|
|
78
|
+
default="tcp",
|
|
79
|
+
description="Broker transport for the runtime container: tcp, tls, or stdio (deprecated)",
|
|
73
80
|
)
|
|
74
81
|
broker_host: str = Field(
|
|
75
82
|
default="host.docker.internal",
|
|
@@ -143,6 +150,15 @@ class SandboxConfig(BaseModel):
|
|
|
143
150
|
|
|
144
151
|
model_config = {"arbitrary_types_allowed": True}
|
|
145
152
|
|
|
153
|
+
@model_validator(mode="after")
|
|
154
|
+
def add_default_volumes(self):
|
|
155
|
+
"""Add default volume mounts based on config flags."""
|
|
156
|
+
if self.mount_current_dir:
|
|
157
|
+
# Insert at beginning so user volumes can override
|
|
158
|
+
if ".:/workspace:rw" not in self.volumes:
|
|
159
|
+
self.volumes.insert(0, ".:/workspace:rw")
|
|
160
|
+
return self
|
|
161
|
+
|
|
146
162
|
|
|
147
163
|
def get_default_sandbox_config() -> SandboxConfig:
|
|
148
164
|
"""Get the default sandbox configuration."""
|
|
@@ -419,12 +419,40 @@ class ContainerRunner:
|
|
|
419
419
|
)
|
|
420
420
|
|
|
421
421
|
# Run container
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
422
|
+
# If TCP broker is active, run it concurrently with the container
|
|
423
|
+
if broker_transport in ("tcp", "tls") and broker_server is not None:
|
|
424
|
+
|
|
425
|
+
async def run_broker_server():
|
|
426
|
+
"""Serve broker connections until explicitly closed."""
|
|
427
|
+
try:
|
|
428
|
+
await broker_server.serve()
|
|
429
|
+
except Exception:
|
|
430
|
+
# Broker server was closed (expected on cleanup)
|
|
431
|
+
pass
|
|
432
|
+
|
|
433
|
+
# Run broker and container concurrently
|
|
434
|
+
broker_task = asyncio.create_task(run_broker_server())
|
|
435
|
+
try:
|
|
436
|
+
result = await self._run_container(
|
|
437
|
+
docker_cmd,
|
|
438
|
+
request,
|
|
439
|
+
timeout=self.config.timeout,
|
|
440
|
+
event_handler=event_handler,
|
|
441
|
+
)
|
|
442
|
+
finally:
|
|
443
|
+
# Cancel broker task when container finishes
|
|
444
|
+
broker_task.cancel()
|
|
445
|
+
try:
|
|
446
|
+
await broker_task
|
|
447
|
+
except asyncio.CancelledError:
|
|
448
|
+
pass
|
|
449
|
+
else:
|
|
450
|
+
result = await self._run_container(
|
|
451
|
+
docker_cmd,
|
|
452
|
+
request,
|
|
453
|
+
timeout=self.config.timeout,
|
|
454
|
+
event_handler=event_handler,
|
|
455
|
+
)
|
|
428
456
|
|
|
429
457
|
result.duration_seconds = time.time() - start_time
|
|
430
458
|
return result
|
|
@@ -16,9 +16,9 @@ Usage:
|
|
|
16
16
|
end
|
|
17
17
|
]]--
|
|
18
18
|
|
|
19
|
-
--
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
-- Provide explicit name so the tool is recorded/mocked as "done"
|
|
20
|
+
return Tool {
|
|
21
|
+
name = "done",
|
|
22
22
|
description = "Signal task completion",
|
|
23
23
|
input = {
|
|
24
24
|
reason = field.string{required = false, description = "Reason for completion"}
|
|
@@ -17,6 +17,7 @@ Note: For direct logging in procedures, use the Log global directly:
|
|
|
17
17
|
]]--
|
|
18
18
|
|
|
19
19
|
local log_tool = Tool {
|
|
20
|
+
name = "log",
|
|
20
21
|
description = "Log a message during procedure execution",
|
|
21
22
|
input = {
|
|
22
23
|
message = field.string{required = true, description = "Message to log"},
|
tactus/testing/context.py
CHANGED
|
@@ -77,7 +77,6 @@ class TactusTestContext:
|
|
|
77
77
|
storage_backend=storage,
|
|
78
78
|
hitl_handler=hitl,
|
|
79
79
|
tool_primitive=tool_primitive, # Inject mocked tool if configured
|
|
80
|
-
skip_agents=bool(self.mock_tools), # Skip agents in mock mode
|
|
81
80
|
openai_api_key=os.environ.get("OPENAI_API_KEY"), # Pass API key for real LLM calls
|
|
82
81
|
log_handler=log_handler, # Enable cost tracking
|
|
83
82
|
source_file_path=str(self.procedure_file.resolve()), # For require() path resolution
|
|
@@ -155,6 +155,23 @@ class TactusDSLVisitor(LuaParserVisitor):
|
|
|
155
155
|
elif func_name == "Tool":
|
|
156
156
|
# Extract config from Tool {...}
|
|
157
157
|
config = self._extract_single_table_arg(func_call)
|
|
158
|
+
if (
|
|
159
|
+
config
|
|
160
|
+
and isinstance(config, dict)
|
|
161
|
+
and isinstance(config.get("name"), str)
|
|
162
|
+
and config.get("name") != var_name
|
|
163
|
+
):
|
|
164
|
+
self.errors.append(
|
|
165
|
+
ValidationMessage(
|
|
166
|
+
level="error",
|
|
167
|
+
message=(
|
|
168
|
+
f"Tool name mismatch: '{var_name} = Tool {{ name = \"{config.get('name')}\" }}'. "
|
|
169
|
+
f"Remove the 'name' field or set it to '{var_name}'."
|
|
170
|
+
),
|
|
171
|
+
location=(self.current_line, self.current_col),
|
|
172
|
+
declaration="Tool",
|
|
173
|
+
)
|
|
174
|
+
)
|
|
158
175
|
self.builder.register_tool(var_name, config if config else {}, None)
|
|
159
176
|
elif func_name == "Toolset":
|
|
160
177
|
# Extract config from Toolset {...}
|
|
@@ -508,28 +525,21 @@ class TactusDSLVisitor(LuaParserVisitor):
|
|
|
508
525
|
if args and len(args) >= 1 and isinstance(args[0], dict):
|
|
509
526
|
self.builder.register_top_level_output(args[0])
|
|
510
527
|
elif func_name == "Tool": # CamelCase only
|
|
511
|
-
# Tool
|
|
512
|
-
#
|
|
513
|
-
if args and len(args) >= 1
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
self.
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
ValidationMessage(
|
|
527
|
-
level="error",
|
|
528
|
-
message=f'Curried syntax Tool "{tool_name}" {{...}} is deprecated. Use assignment syntax: {tool_name} = Tool {{...}}',
|
|
529
|
-
location=(self.current_line, self.current_col),
|
|
530
|
-
declaration="Tool",
|
|
531
|
-
)
|
|
532
|
-
)
|
|
528
|
+
# Curried syntax (Tool "name" {...} / Tool("name", ...)) is not supported.
|
|
529
|
+
# Use assignment syntax: my_tool = Tool { ... }.
|
|
530
|
+
if args and len(args) >= 1 and isinstance(args[0], str):
|
|
531
|
+
tool_name = args[0]
|
|
532
|
+
self.errors.append(
|
|
533
|
+
ValidationMessage(
|
|
534
|
+
level="error",
|
|
535
|
+
message=(
|
|
536
|
+
f'Curried Tool syntax is not supported: Tool "{tool_name}" {{...}}. '
|
|
537
|
+
f"Use assignment syntax: {tool_name} = Tool {{...}}."
|
|
538
|
+
),
|
|
539
|
+
location=(self.current_line, self.current_col),
|
|
540
|
+
declaration="Tool",
|
|
541
|
+
)
|
|
542
|
+
)
|
|
533
543
|
elif func_name == "Toolset": # CamelCase only
|
|
534
544
|
# Toolset("name", {config})
|
|
535
545
|
# or new curried syntax: Toolset "name" { config }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tactus
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.28.0
|
|
4
4
|
Summary: Tactus: Lua-based DSL for agentic workflows
|
|
5
5
|
Project-URL: Homepage, https://github.com/AnthusAI/Tactus
|
|
6
6
|
Project-URL: Documentation, https://github.com/AnthusAI/Tactus/tree/main/docs
|
|
@@ -636,6 +636,22 @@ researcher({
|
|
|
636
636
|
|
|
637
637
|
See `examples/14-feature-per-turn-tools.tac` for a complete working example.
|
|
638
638
|
|
|
639
|
+
### Checkpointed Steps (Determinism)
|
|
640
|
+
|
|
641
|
+
For durable execution, any operation that touches external state (randomness, time, APIs not in tools) must be checkpointed. Tactus provides `Step.checkpoint` for this:
|
|
642
|
+
|
|
643
|
+
```lua
|
|
644
|
+
-- Non-deterministic operation wrapped in checkpoint
|
|
645
|
+
local data = Step.checkpoint(function()
|
|
646
|
+
return http_get("https://api.example.com/data")
|
|
647
|
+
end)
|
|
648
|
+
|
|
649
|
+
-- On replay, the function is NOT called again.
|
|
650
|
+
-- The previously saved 'data' is returned immediately.
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
This ensures that when a procedure resumes after a pause (e.g. waiting for a human), it doesn't re-execute side effects or get different random values.
|
|
654
|
+
|
|
639
655
|
### File I/O Operations
|
|
640
656
|
|
|
641
657
|
Tactus provides safe file I/O operations for reading and writing data files, with all operations restricted to the current working directory for security.
|
|
@@ -1085,6 +1101,60 @@ default_provider: openai
|
|
|
1085
1101
|
default_model: gpt-4o
|
|
1086
1102
|
```
|
|
1087
1103
|
|
|
1104
|
+
### DSPy Integration
|
|
1105
|
+
|
|
1106
|
+
Tactus provides first-class support for **DSPy Modules and Signatures**, enabling you to build declarative, self-optimizing AI components directly within your agent workflows.
|
|
1107
|
+
|
|
1108
|
+
**Modules & Signatures:**
|
|
1109
|
+
|
|
1110
|
+
Instead of hand-tuning prompts, define what you want the model to do using typed signatures:
|
|
1111
|
+
|
|
1112
|
+
```lua
|
|
1113
|
+
-- Configure the Language Model for DSPy
|
|
1114
|
+
LM("openai/gpt-4o")
|
|
1115
|
+
|
|
1116
|
+
-- Define a module with a typed signature
|
|
1117
|
+
summarizer = Module {
|
|
1118
|
+
signature = "text -> summary",
|
|
1119
|
+
strategy = "chain_of_thought" -- Use Chain of Thought reasoning
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
-- Or define complex signatures with specific fields
|
|
1123
|
+
classifier = Module {
|
|
1124
|
+
signature = Signature {
|
|
1125
|
+
input = {
|
|
1126
|
+
text = field.string{description = "The customer email to classify"}
|
|
1127
|
+
},
|
|
1128
|
+
output = {
|
|
1129
|
+
category = field.string{description = "Support category (Billing, Tech, Sales)"},
|
|
1130
|
+
priority = field.string{description = "Priority level (Low, High, Critical)"}
|
|
1131
|
+
}
|
|
1132
|
+
},
|
|
1133
|
+
strategy = "predict"
|
|
1134
|
+
}
|
|
1135
|
+
```
|
|
1136
|
+
|
|
1137
|
+
**Using Modules:**
|
|
1138
|
+
|
|
1139
|
+
Modules are callable just like Agents or Tools:
|
|
1140
|
+
|
|
1141
|
+
```lua
|
|
1142
|
+
Procedure {
|
|
1143
|
+
function(input)
|
|
1144
|
+
-- Call the module
|
|
1145
|
+
local result = classifier({text = input.email})
|
|
1146
|
+
|
|
1147
|
+
if result.priority == "Critical" then
|
|
1148
|
+
human_escalation({context = result})
|
|
1149
|
+
else
|
|
1150
|
+
auto_responder({category = result.category})
|
|
1151
|
+
end
|
|
1152
|
+
end
|
|
1153
|
+
}
|
|
1154
|
+
```
|
|
1155
|
+
|
|
1156
|
+
This brings the power of DSPy's programmable LLM interfaces into Tactus's durable, orchestrated environment.
|
|
1157
|
+
|
|
1088
1158
|
### Asynchronous Execution
|
|
1089
1159
|
|
|
1090
1160
|
Tactus is built on **async I/O** from the ground up, making it ideal for LLM-based workflows where you spend most of your time waiting for API responses.
|
|
@@ -1275,6 +1345,21 @@ Then reference them in your procedure:
|
|
|
1275
1345
|
local approved = Human.approve("confirm_publish")
|
|
1276
1346
|
```
|
|
1277
1347
|
|
|
1348
|
+
**System Alerts:**
|
|
1349
|
+
|
|
1350
|
+
Send alerts to your monitoring infrastructure (Datadog, PagerDuty) directly from the workflow:
|
|
1351
|
+
|
|
1352
|
+
```lua
|
|
1353
|
+
System.alert({
|
|
1354
|
+
message = "Failure rate exceeded threshold",
|
|
1355
|
+
level = "error", -- info, warning, error, critical
|
|
1356
|
+
context = {
|
|
1357
|
+
current_rate = 0.15,
|
|
1358
|
+
threshold = 0.05
|
|
1359
|
+
}
|
|
1360
|
+
})
|
|
1361
|
+
```
|
|
1362
|
+
|
|
1278
1363
|
### Cost Tracking & Metrics
|
|
1279
1364
|
|
|
1280
1365
|
Tactus provides **comprehensive cost and performance tracking** for all LLM calls. Every agent interaction is monitored with detailed metrics, giving you complete visibility into costs, performance, and behavior.
|
|
@@ -1360,20 +1445,37 @@ The AI agent space is crowded. This section explains how Tactus differs from alt
|
|
|
1360
1445
|
|
|
1361
1446
|
### DSPy
|
|
1362
1447
|
|
|
1363
|
-
[DSPy](https://dspy.ai) (Declarative Self-improving Python)
|
|
1448
|
+
[DSPy](https://dspy.ai) (Declarative Self-improving Python) is the engine that powers Tactus's intelligence layer. Tactus integrates DSPy directly, allowing you to define DSPy Modules, Signatures, and Optimizers within your `.tac` files using a clean Lua syntax.
|
|
1449
|
+
|
|
1450
|
+
While DSPy provides the primitives for programming with language models (optimizing prompts, few-shot examples, and reasoning steps), Tactus provides the **orchestration layer** that makes these components production-ready:
|
|
1364
1451
|
|
|
1365
|
-
|
|
1452
|
+
- **Durability**: Tactus handles checkpointing and resuming DSPy module calls transparently.
|
|
1453
|
+
- **Orchestration**: Tactus manages the control flow (loops, conditionals) around your DSPy modules.
|
|
1454
|
+
- **Human-in-the-Loop**: Tactus allows humans to inspect, approve, or correct DSPy module outputs.
|
|
1455
|
+
- **Sandboxing**: Tactus runs DSPy components in a safe, sandboxed environment suitable for user-contributed code.
|
|
1456
|
+
|
|
1457
|
+
You can use Tactus to define standard DSPy modules:
|
|
1458
|
+
|
|
1459
|
+
```lua
|
|
1460
|
+
-- Define a DSPy Module with a typed signature
|
|
1461
|
+
qa = Module {
|
|
1462
|
+
signature = "question -> answer",
|
|
1463
|
+
strategy = "chain_of_thought"
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
-- Invoke it as part of a durable workflow
|
|
1467
|
+
local result = qa({question = "How does this work?"})
|
|
1468
|
+
```
|
|
1366
1469
|
|
|
1367
|
-
|
|
1470
|
+
Tactus and DSPy work together: DSPy handles the *thinking* (optimizing how to get the best answer), while Tactus handles the *doing* (ensuring the workflow completes reliably, even if it takes days).
|
|
1368
1471
|
|
|
1369
|
-
| | DSPy | Tactus |
|
|
1370
|
-
|
|
1371
|
-
| **
|
|
1372
|
-
| **
|
|
1373
|
-
| **
|
|
1374
|
-
| **
|
|
1375
|
-
| **
|
|
1376
|
-
| **Target** | Researchers optimizing prompts | Engineers building production workflows |
|
|
1472
|
+
| | DSPy (Python) | Tactus (Lua) |
|
|
1473
|
+
|---|---|---|
|
|
1474
|
+
| **Role** | Intelligence Engine | Orchestration Engine |
|
|
1475
|
+
| **Focus** | Prompt optimization, reasoning | Durability, HITL, Sandboxing |
|
|
1476
|
+
| **Definition** | Python classes | Lua DSL primitives |
|
|
1477
|
+
| **State** | In-memory | Persisted & Resumable |
|
|
1478
|
+
| **Optimization** | Automatic (Teleprompters) | Agent-driven or Manual |
|
|
1377
1479
|
|
|
1378
1480
|
### LangGraph
|
|
1379
1481
|
|
|
@@ -1409,17 +1511,18 @@ The major AI companies have released their own agent frameworks:
|
|
|
1409
1511
|
|
|
1410
1512
|
- **[Meta Llama Stack](https://ai.meta.com/blog/meta-llama-3-1/)** — Standardized interfaces for building agentic applications with Llama models. More of an API specification than a workflow framework.
|
|
1411
1513
|
|
|
1412
|
-
These frameworks are valuable if you're committed to a specific vendor's ecosystem. Tactus is model-agnostic (via
|
|
1514
|
+
These frameworks are valuable if you're committed to a specific vendor's ecosystem. Tactus is model-agnostic (via [DSPy](https://dspy.ai)) and designed to run anywhere—local, cloud, or AWS Lambda Durable Functions.
|
|
1413
1515
|
|
|
1414
1516
|
### Other Tools
|
|
1415
1517
|
|
|
1416
|
-
- **[Pydantic-AI](https://github.com/pydantic/pydantic-ai)** —
|
|
1518
|
+
- **[Pydantic-AI](https://github.com/pydantic/pydantic-ai)** — Used for type-safe tool definitions and message structures.
|
|
1417
1519
|
|
|
1418
1520
|
- **[Guidance](https://github.com/guidance-ai/guidance)** (Microsoft) — Interleaves constrained generation with control flow. Focuses on token-level control during generation rather than workflow orchestration.
|
|
1419
1521
|
|
|
1420
1522
|
## Complete Feature List
|
|
1421
1523
|
|
|
1422
1524
|
- **Durable Execution**: Automatic position-based checkpointing for all operations (agent turns, model predictions, sub-procedure calls, HITL interactions) with replay-based recovery—resume from exactly where you left off after crashes, timeouts, or pauses
|
|
1525
|
+
- **DSPy Integration**: First-class support for DSPy Modules and Signatures, enabling declarative machine learning components and prompt optimization alongside agentic workflows
|
|
1423
1526
|
- **Model Primitive**: First-class support for ML inference (PyTorch, HTTP, HuggingFace Transformers) with automatic checkpointing—distinct from conversational agents for classification, prediction, and transformation tasks
|
|
1424
1527
|
- **Script Mode**: Write procedures without explicit `main` definitions—top-level `input`/`output` declarations and code automatically wrapped as the main procedure
|
|
1425
1528
|
- **State Management**: Typed, schema-validated persistent state with automatic initialization from defaults and runtime validation
|
|
@@ -1434,7 +1537,7 @@ These frameworks are valuable if you're committed to a specific vendor's ecosyst
|
|
|
1434
1537
|
- **Context Engineering**: Fine-grained control over conversation history per agent
|
|
1435
1538
|
- **Typed Input/Output**: JSON Schema validation with UI generation support using `input`/`output`/`state` declarations
|
|
1436
1539
|
- **Pluggable Backends**: Storage, HITL, and chat recording via Pydantic protocols
|
|
1437
|
-
- **LLM Integration**: Works with OpenAI and Bedrock via [
|
|
1540
|
+
- **LLM Integration**: Works with OpenAI and Bedrock via [DSPy](https://dspy.ai)
|
|
1438
1541
|
- **Standalone CLI**: Run workflows without any infrastructure
|
|
1439
1542
|
- **Type-Safe**: Pydantic models throughout for validation and type safety
|
|
1440
1543
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
tactus/__init__.py,sha256=
|
|
1
|
+
tactus/__init__.py,sha256=8Tz1eNKHHz9MXIcRw6cUoT1NdeOpUm4R4JjXnudVXZE,1245
|
|
2
2
|
tactus/adapters/__init__.py,sha256=lU8uUxuryFRIpVrn_KeVK7aUhsvOT1tYsuE3FOOIFpI,289
|
|
3
|
-
tactus/adapters/broker_log.py,sha256=
|
|
3
|
+
tactus/adapters/broker_log.py,sha256=mIjARt1Q6ouWVbVri6zep1e8tzm9y28l4WOEdqiK39Q,2849
|
|
4
4
|
tactus/adapters/cli_hitl.py,sha256=3dH58du0lN4k-OvQrAHrAqHFqBjolqNKFb94JaNHtn8,6964
|
|
5
5
|
tactus/adapters/cli_log.py,sha256=uyTOLY9y26foAr-8COEYP6dejdO_Huur4i0DLaowfAY,8894
|
|
6
6
|
tactus/adapters/cost_collector_log.py,sha256=Ha3pFMdC0HJ8eBnZpM1VRLm-94RKelu5PEPDgFgNKow,1701
|
|
@@ -16,15 +16,16 @@ tactus/backends/http_backend.py,sha256=D2N91I5bnjhHMLG84-U-BRS-mIuwoQq72Feffi7At
|
|
|
16
16
|
tactus/backends/model_backend.py,sha256=P8dCUpDxJmA8_EO1snZuXyIyUZ_BlqReeC6zenO7Kv0,763
|
|
17
17
|
tactus/backends/pytorch_backend.py,sha256=I7H7UTa_Scx9_FtmPWn-G4noadaNVEQj-9Kjtjpgl6E,3305
|
|
18
18
|
tactus/broker/__init__.py,sha256=UTvqLofrgE3c4m6u2iNOg5R7BrS4dmfzMRO4Oq_0A9U,396
|
|
19
|
-
tactus/broker/client.py,sha256=
|
|
20
|
-
tactus/broker/
|
|
19
|
+
tactus/broker/client.py,sha256=sDi1Cimuv0zH5S4n597nnUy_qis7pLBZf5IkwF81oDc,8618
|
|
20
|
+
tactus/broker/protocol.py,sha256=fnVgMKU_R7oK2xBATnrYSH_r2R-yOmV2o_pJYw1JvVk,5238
|
|
21
|
+
tactus/broker/server.py,sha256=ciP6FkPBfenfzrTNzkr6If7kQFs4B7mLU77A0hh7y_8,17154
|
|
21
22
|
tactus/broker/stdio.py,sha256=JXkEz-PCU3IQXNkt16YJtYmwkR43eS6CfjxAHc-YCfQ,439
|
|
22
23
|
tactus/cli/__init__.py,sha256=kVhdCkwWEPdt3vn9si-iKvh6M9817aOH6rLSsNzRuyg,80
|
|
23
|
-
tactus/cli/app.py,sha256=
|
|
24
|
+
tactus/cli/app.py,sha256=97lrjIQxDGM5PuvPZx9CeTZc0CyT1tBhLOl98oej3zE,83496
|
|
24
25
|
tactus/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
26
|
tactus/core/__init__.py,sha256=TK5rWr3HmOO_igFa5ESGp6teWwS58vnvQhIWqkcgqwk,880
|
|
26
27
|
tactus/core/config_manager.py,sha256=u90XChTeb2reZ3I6c3o_zI2UlzlFCNtL9-NhE1Vm6L0,31577
|
|
27
|
-
tactus/core/dsl_stubs.py,sha256
|
|
28
|
+
tactus/core/dsl_stubs.py,sha256=-gio8VFQ_8atH3SOPC2s2bimXu1vYZc-I3Z6yJqdhIU,76070
|
|
28
29
|
tactus/core/exceptions.py,sha256=HruvJQ4yIi78hOvvHviNZolcraMwXrlGQzxHqYFQapA,1468
|
|
29
30
|
tactus/core/execution_context.py,sha256=WNd55_JhmkDifA9Td3xIs8to5bwGDlCgPcbvkvLYAv0,16658
|
|
30
31
|
tactus/core/lua_sandbox.py,sha256=WuXRuXSl9ylU0y3ZMvyDWjWiG6GdLVn2csMY-2Zmrbg,18262
|
|
@@ -32,15 +33,15 @@ tactus/core/message_history_manager.py,sha256=e3_seV6bWSJVicrZYf2LmaQBvroDXDRc5T
|
|
|
32
33
|
tactus/core/mocking.py,sha256=1MKtg8FHCYj-Goihi5b8xNNYo-MDuzSpsHEX_e7bnfg,9217
|
|
33
34
|
tactus/core/output_validator.py,sha256=a-a_L-8oondMA4dzJMekhlHUF0vA_G_prMdFaBu5vhU,7823
|
|
34
35
|
tactus/core/registry.py,sha256=1FKjj9wcTbz3VhCBGO6ylSb5WAaN-liLCQFe06nPfU4,20128
|
|
35
|
-
tactus/core/runtime.py,sha256=
|
|
36
|
+
tactus/core/runtime.py,sha256=4iYe9ONVKTNc9QVf2Z2O99ofk_8shUYm0fn6oSwfzAg,122904
|
|
36
37
|
tactus/core/template_resolver.py,sha256=6zRq4zT1lRHdLoa7M-yoLx4hFZ9RcjH9Y0EdaAtW9FU,4033
|
|
37
38
|
tactus/core/yaml_parser.py,sha256=s7VB5Nijy6ReQE7ixlmvZArqupXs_sWP4EY4pCLv25k,13400
|
|
38
39
|
tactus/core/dependencies/__init__.py,sha256=28-TM7_i-JqTD3hvkq1kMzr__A8VjfIKXymdW9mn5NM,362
|
|
39
40
|
tactus/core/dependencies/registry.py,sha256=bgRdqJJTUrnQlu0wvjv2In1EPq7prZq-b9eBDhE3rmE,6114
|
|
40
41
|
tactus/docker/Dockerfile,sha256=fnK5kZlgM-L7vboiwfTqcs70OsZsvh1ba4YzRxie138,1887
|
|
41
|
-
tactus/docker/entrypoint.sh,sha256
|
|
42
|
+
tactus/docker/entrypoint.sh,sha256=pL-1MwMdjD1fGgRZYkBeXmJZg57Knmub9ETLYAANvOg,1985
|
|
42
43
|
tactus/dspy/__init__.py,sha256=beUkvMUFdPvZE9-bEOfRo2TH-FoCvPT_L9_dpJPW324,1226
|
|
43
|
-
tactus/dspy/agent.py,sha256
|
|
44
|
+
tactus/dspy/agent.py,sha256=-GFvV6d-1ek-IMn-0ML_jFEL2a-2DsEhyKmgpeTdOmQ,43484
|
|
44
45
|
tactus/dspy/broker_lm.py,sha256=EaXlJcUhfM0NV0fD1rASYKSO5gm846KRS5BoT0iO4zs,6239
|
|
45
46
|
tactus/dspy/config.py,sha256=B22ON9Zp-dabI4NYeMbZ5lUL4kqihR7FQ8Z8xKT_eL8,6567
|
|
46
47
|
tactus/dspy/history.py,sha256=0yGi3P5ruRUPoRyaCWsUDeuEYYsfproc_7pMVZuhmUo,5980
|
|
@@ -69,7 +70,7 @@ tactus/primitives/state.py,sha256=o3rsz-P8R2O66nsYmXOjn54342NIn6ldqTqp9XvgPLI,56
|
|
|
69
70
|
tactus/primitives/step.py,sha256=2STt1M_9R0Ga5YHScA5i1eXqqIDI_S_q9E4GSyWhM2Y,7175
|
|
70
71
|
tactus/primitives/system.py,sha256=jIzDLuL8a6owTPokAb7giwKYOxEtxmacntkNzzu8BWU,3350
|
|
71
72
|
tactus/primitives/tool.py,sha256=KppWrbVxPwZ6aRk2Lw5ki1ACwV_65yK2wSFWaH3da88,12643
|
|
72
|
-
tactus/primitives/tool_handle.py,sha256=
|
|
73
|
+
tactus/primitives/tool_handle.py,sha256=x6D4Zi-x-werFVBgB-F3mTtIMRbkYjPq3IBjjs8VSTc,9085
|
|
73
74
|
tactus/primitives/toolset.py,sha256=T9DtULPgDX7CGBnfOtEx6SsKEtJPWrKXMOnHJer_spY,7779
|
|
74
75
|
tactus/protocols/__init__.py,sha256=w5PFgHq8ov7BbNKcgCmbPSQ_E9l6F8xwrtxEQ2YSWO4,783
|
|
75
76
|
tactus/protocols/chat_recorder.py,sha256=dswAHpwlxq30GTGKT-ktCIKCaixn5izEMSb7sbiZARE,2074
|
|
@@ -86,8 +87,8 @@ tactus/providers/bedrock.py,sha256=cVNDV7uHhCnnL6BNl7DFF8OwkD9ZYqa9CP2wXMcCJGY,3
|
|
|
86
87
|
tactus/providers/google.py,sha256=wgZ3eiQif1rq1T8BK5V2kL_QVCmqBQZuWLz37y9cxOQ,3123
|
|
87
88
|
tactus/providers/openai.py,sha256=3qSXfdELTHdU7vuRSxQrtnfNctt0HhrePOLFj3YlViA,2692
|
|
88
89
|
tactus/sandbox/__init__.py,sha256=UCBvPD63szvSdwSzpznLW-cnJOgGkVHiKcmJtsAmnuA,1424
|
|
89
|
-
tactus/sandbox/config.py,sha256=
|
|
90
|
-
tactus/sandbox/container_runner.py,sha256=
|
|
90
|
+
tactus/sandbox/config.py,sha256=KuWtQwxHGVz3P_My5bOvMor3cxZMW8Y-wTLQszXP4Cg,5582
|
|
91
|
+
tactus/sandbox/container_runner.py,sha256=eefK37PoV7hclJdw5uodC32rzuFvNLNDavnob1Wymtk,39561
|
|
91
92
|
tactus/sandbox/docker_manager.py,sha256=SGv0IEN9usgyQRvbonrgOLm6GICel8ifzBAopAwOyt0,13949
|
|
92
93
|
tactus/sandbox/entrypoint.py,sha256=Jbw7ZIOhBygiZa-LHoQAbQg4VJBzK_XrN8wnf1xD5xg,6803
|
|
93
94
|
tactus/sandbox/protocol.py,sha256=1h36423pOFAwwZBgzMkeAIIjan1asgmBiIjN234YlpQ,6060
|
|
@@ -102,12 +103,12 @@ tactus/stdlib/io/hdf5.py,sha256=7ELLaQZI1GOsycU1a60J6RTPNLH7EMdaPAYlNx0dQLA,3025
|
|
|
102
103
|
tactus/stdlib/io/json.py,sha256=P6C6rIwAxY97MivCanxKF8TmRotIUxBlHcuv8etmLu8,2641
|
|
103
104
|
tactus/stdlib/io/parquet.py,sha256=hycr0pjqysjhggHx7_UZJL_jkeP1wz8BCozL39EWk-0,2045
|
|
104
105
|
tactus/stdlib/io/tsv.py,sha256=456V2g-dp0mOTxo0ojM-rQl-LlmeV6WAVh0HmEDd_kQ,2350
|
|
105
|
-
tactus/stdlib/tac/tactus/tools/done.tac,sha256=
|
|
106
|
-
tactus/stdlib/tac/tactus/tools/log.tac,sha256=
|
|
106
|
+
tactus/stdlib/tac/tactus/tools/done.tac,sha256=aCQzwL7SXq-rx18QGq3NLKoT_eweoVRObBkCSu4lkzo,732
|
|
107
|
+
tactus/stdlib/tac/tactus/tools/log.tac,sha256=oRwnKxQZsZPXmZcGABZ6zM4NASV54tGAMClfsX8QNGk,1392
|
|
107
108
|
tactus/testing/README.md,sha256=8AI-N9Llw0cQPweVkeUctEPsAOUviHrTZb48mF82EDE,7042
|
|
108
109
|
tactus/testing/__init__.py,sha256=M5b3r9E0vkltfhqfIOSASk-qp6fDnm3FBxc9dDBPUhU,1540
|
|
109
110
|
tactus/testing/behave_integration.py,sha256=mtAM30Uhj57_raGbPxAyMvfT-vnGnTm01UyeUqyE0H8,14887
|
|
110
|
-
tactus/testing/context.py,sha256=
|
|
111
|
+
tactus/testing/context.py,sha256=az7eQi9pZfjIYxIv2j02e9OGPNbr8Hww-UIRCEosvVY,14190
|
|
111
112
|
tactus/testing/eval_models.py,sha256=UI3geZp4vilbn3Jt4Mjy95luRVON3T4sGnAwlpb7jLo,3540
|
|
112
113
|
tactus/testing/evaluation_runner.py,sha256=_wemv2yf-N6wjIyhwxVJyoH4FABlKoBv-OKTcgwNm0Q,6908
|
|
113
114
|
tactus/testing/evaluators.py,sha256=NW_LHhssdMRYCCoYmtJIsst-DEsk8iBVebsxRyHx7I0,20751
|
|
@@ -137,7 +138,7 @@ tactus/validation/LuaParserBase.py,sha256=o3klCIY0ANkVCU0VHml0IOYE4CdEledeoyoIAP
|
|
|
137
138
|
tactus/validation/README.md,sha256=AS6vr4blY7IKWRsj4wuvWBHVMTc5fto7IgNmv-Rjkdo,5366
|
|
138
139
|
tactus/validation/__init__.py,sha256=rnap-YvNievWigYYUewuXBcLtAdjZ8YpeJDYS1T7XZM,153
|
|
139
140
|
tactus/validation/error_listener.py,sha256=ANaQHPzRSGQMgreYqZ4ZvIKGENj55FnrEQYUmqFvGaY,619
|
|
140
|
-
tactus/validation/semantic_visitor.py,sha256=
|
|
141
|
+
tactus/validation/semantic_visitor.py,sha256=pQ8WV_9kilY7orDbn7YGFTyX4DrcjWfoApxVL1vwqcU,36882
|
|
141
142
|
tactus/validation/validator.py,sha256=Vut4nWoNVbm1n_RRbdLVLJyBb6S29KjnxXi-SrRQd3Y,4842
|
|
142
143
|
tactus/validation/generated/LuaLexer.interp,sha256=B-Xb6HNXS7YYYQB_cvsWzf8OQLFnEhZHDN5vCOyP3yw,20444
|
|
143
144
|
tactus/validation/generated/LuaLexer.py,sha256=6B-HNB_vAp3bA5iACLvMWw0R4KFENsuiG7bccysxbRQ,67252
|
|
@@ -151,8 +152,8 @@ tactus/validation/generated/LuaParserVisitor.py,sha256=ageKSmHPxnO3jBS2fBtkmYBOd
|
|
|
151
152
|
tactus/validation/generated/__init__.py,sha256=5gWlwRI0UvmHw2fnBpj_IG6N8oZeabr5tbj1AODDvjc,196
|
|
152
153
|
tactus/validation/grammar/LuaLexer.g4,sha256=t2MXiTCr127RWAyQGvamkcU_m4veqPzSuHUtAKwalw4,2771
|
|
153
154
|
tactus/validation/grammar/LuaParser.g4,sha256=ceZenb90BdiZmVdOxMGj9qJk3QbbWVZe5HUqPgoePfY,3202
|
|
154
|
-
tactus-0.
|
|
155
|
-
tactus-0.
|
|
156
|
-
tactus-0.
|
|
157
|
-
tactus-0.
|
|
158
|
-
tactus-0.
|
|
155
|
+
tactus-0.28.0.dist-info/METADATA,sha256=hvZRdVInGcwogSbsULPG4vXf4hNUCAQrT6ByzL6f0VM,58441
|
|
156
|
+
tactus-0.28.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
157
|
+
tactus-0.28.0.dist-info/entry_points.txt,sha256=vWseqty8m3z-Worje0IYxlioMjPDCoSsm0AtY4GghBY,47
|
|
158
|
+
tactus-0.28.0.dist-info/licenses/LICENSE,sha256=ivohBcAIYnaLPQ-lKEeCXSMvQUVISpQfKyxHBHoa4GA,1066
|
|
159
|
+
tactus-0.28.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|