tactus 0.37.0__py3-none-any.whl → 0.39.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/channels/base.py +2 -0
- tactus/cli/app.py +212 -57
- tactus/core/compaction.py +17 -0
- tactus/core/context_assembler.py +73 -0
- tactus/core/context_models.py +41 -0
- tactus/core/dsl_stubs.py +568 -17
- tactus/core/exceptions.py +8 -0
- tactus/core/execution_context.py +1 -1
- tactus/core/mocking.py +12 -0
- tactus/core/registry.py +142 -0
- tactus/core/retrieval.py +317 -0
- tactus/core/retriever_tasks.py +30 -0
- tactus/core/runtime.py +441 -75
- tactus/dspy/agent.py +143 -82
- tactus/dspy/config.py +16 -0
- tactus/dspy/module.py +12 -1
- tactus/ide/coding_assistant.py +2 -2
- tactus/plugins/__init__.py +3 -0
- tactus/plugins/noaa.py +76 -0
- tactus/primitives/handles.py +79 -7
- tactus/sandbox/config.py +1 -1
- tactus/sandbox/container_runner.py +2 -0
- tactus/sandbox/entrypoint.py +51 -8
- tactus/sandbox/protocol.py +5 -0
- tactus/stdlib/README.md +10 -1
- tactus/stdlib/biblicus/__init__.py +3 -0
- tactus/stdlib/biblicus/text.py +208 -0
- tactus/stdlib/tac/biblicus/text.tac +32 -0
- tactus/stdlib/tac/tactus/biblicus.spec.tac +179 -0
- tactus/stdlib/tac/tactus/corpora/base.tac +42 -0
- tactus/stdlib/tac/tactus/corpora/filesystem.tac +5 -0
- tactus/stdlib/tac/tactus/retrievers/base.tac +37 -0
- tactus/stdlib/tac/tactus/retrievers/embedding_index_file.tac +6 -0
- tactus/stdlib/tac/tactus/retrievers/embedding_index_inmemory.tac +6 -0
- tactus/stdlib/tac/tactus/retrievers/index.md +137 -0
- tactus/stdlib/tac/tactus/retrievers/init.tac +11 -0
- tactus/stdlib/tac/tactus/retrievers/sqlite_full_text_search.tac +6 -0
- tactus/stdlib/tac/tactus/retrievers/tf_vector.tac +6 -0
- tactus/testing/behave_integration.py +2 -0
- tactus/testing/context.py +4 -0
- tactus/validation/semantic_visitor.py +430 -88
- tactus/validation/validator.py +142 -2
- {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/METADATA +3 -2
- {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/RECORD +48 -28
- {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/WHEEL +0 -0
- {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/entry_points.txt +0 -0
- {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
local function merge_defaults(defaults, config)
|
|
2
|
+
local merged = {}
|
|
3
|
+
if defaults then
|
|
4
|
+
for key, value in pairs(defaults) do
|
|
5
|
+
merged[key] = value
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
if config then
|
|
9
|
+
for key, value in pairs(config) do
|
|
10
|
+
merged[key] = value
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
return merged
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
local function normalize_corpus_config(config, defaults)
|
|
17
|
+
local merged = merge_defaults(defaults, config or {})
|
|
18
|
+
if merged.root ~= nil and merged.corpus_root == nil then
|
|
19
|
+
merged.corpus_root = merged.root
|
|
20
|
+
merged.root = nil
|
|
21
|
+
end
|
|
22
|
+
return merged
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
local function wrap_corpus(defaults)
|
|
26
|
+
local function constructor(config)
|
|
27
|
+
return _tactus_internal_corpus(normalize_corpus_config(config, defaults))
|
|
28
|
+
end
|
|
29
|
+
local cls = {}
|
|
30
|
+
function cls:new(config)
|
|
31
|
+
return constructor(config)
|
|
32
|
+
end
|
|
33
|
+
return setmetatable(cls, {
|
|
34
|
+
__call = function(_, config)
|
|
35
|
+
return constructor(config)
|
|
36
|
+
end,
|
|
37
|
+
})
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
wrap_corpus = wrap_corpus,
|
|
42
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
local function merge_defaults(defaults, config)
|
|
2
|
+
local merged = {}
|
|
3
|
+
if defaults then
|
|
4
|
+
for key, value in pairs(defaults) do
|
|
5
|
+
merged[key] = value
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
if config then
|
|
9
|
+
for key, value in pairs(config) do
|
|
10
|
+
merged[key] = value
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
return merged
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
local corpora_base = require("tactus.corpora.base")
|
|
17
|
+
|
|
18
|
+
local function wrap_retriever(defaults)
|
|
19
|
+
local function constructor(config)
|
|
20
|
+
local merged = merge_defaults(defaults, config or {})
|
|
21
|
+
return _tactus_internal_retriever(merged)
|
|
22
|
+
end
|
|
23
|
+
local cls = {}
|
|
24
|
+
function cls:new(config)
|
|
25
|
+
return constructor(config)
|
|
26
|
+
end
|
|
27
|
+
return setmetatable(cls, {
|
|
28
|
+
__call = function(_, config)
|
|
29
|
+
return constructor(config)
|
|
30
|
+
end,
|
|
31
|
+
})
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
wrap_corpus = corpora_base.wrap_corpus,
|
|
36
|
+
wrap_retriever = wrap_retriever,
|
|
37
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Retriever Modules
|
|
2
|
+
|
|
3
|
+
Tactus exposes Biblicus-backed retrievers as Lua modules so you can select a retriever explicitly at the top of your `.tac` file.
|
|
4
|
+
|
|
5
|
+
## Embedding index (file-backed)
|
|
6
|
+
|
|
7
|
+
```lua
|
|
8
|
+
local FilesystemCorpus = require("tactus.corpora.filesystem")
|
|
9
|
+
local vector = require("tactus.retrievers.embedding_index_file")
|
|
10
|
+
|
|
11
|
+
support_notes = FilesystemCorpus.Corpus {
|
|
12
|
+
root = "corpora/support-notes",
|
|
13
|
+
configuration = {
|
|
14
|
+
pipeline = {
|
|
15
|
+
extract = {
|
|
16
|
+
-- extraction steps (optional)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
support_search = vector.Retriever {
|
|
23
|
+
corpus = support_notes,
|
|
24
|
+
configuration = {
|
|
25
|
+
pipeline = {
|
|
26
|
+
index = {
|
|
27
|
+
embedding_provider = { provider_id = "hash-embedding", dimensions = 64 }
|
|
28
|
+
},
|
|
29
|
+
query = {
|
|
30
|
+
limit = 3,
|
|
31
|
+
maximum_total_characters = 1200
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Embedding index (in-memory)
|
|
39
|
+
|
|
40
|
+
```lua
|
|
41
|
+
local FilesystemCorpus = require("tactus.corpora.filesystem")
|
|
42
|
+
local vector = require("tactus.retrievers.embedding_index_inmemory")
|
|
43
|
+
|
|
44
|
+
notes = FilesystemCorpus.Corpus {
|
|
45
|
+
root = "corpora/notes",
|
|
46
|
+
configuration = {
|
|
47
|
+
pipeline = {
|
|
48
|
+
extract = {
|
|
49
|
+
-- extraction steps (optional)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
search = vector.Retriever {
|
|
56
|
+
corpus = notes,
|
|
57
|
+
configuration = {
|
|
58
|
+
pipeline = {
|
|
59
|
+
index = {
|
|
60
|
+
embedding_provider = { provider_id = "hash-embedding", dimensions = 64 },
|
|
61
|
+
maximum_cache_total_items = 5000
|
|
62
|
+
},
|
|
63
|
+
query = {
|
|
64
|
+
limit = 2
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## SQLite full-text search
|
|
72
|
+
|
|
73
|
+
```lua
|
|
74
|
+
local FilesystemCorpus = require("tactus.corpora.filesystem")
|
|
75
|
+
local vector = require("tactus.retrievers.sqlite_full_text_search")
|
|
76
|
+
|
|
77
|
+
notes = FilesystemCorpus.Corpus {
|
|
78
|
+
root = "corpora/notes",
|
|
79
|
+
configuration = {
|
|
80
|
+
pipeline = {
|
|
81
|
+
extract = {
|
|
82
|
+
-- extraction steps (optional)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
search = vector.Retriever {
|
|
89
|
+
corpus = notes,
|
|
90
|
+
configuration = {
|
|
91
|
+
pipeline = {
|
|
92
|
+
index = {
|
|
93
|
+
snippet_characters = 400,
|
|
94
|
+
chunk_size = 800,
|
|
95
|
+
chunk_overlap = 200
|
|
96
|
+
},
|
|
97
|
+
query = {
|
|
98
|
+
limit = 2,
|
|
99
|
+
maximum_total_characters = 1200
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## TF vector (term-frequency)
|
|
107
|
+
|
|
108
|
+
```lua
|
|
109
|
+
local FilesystemCorpus = require("tactus.corpora.filesystem")
|
|
110
|
+
local vector = require("tactus.retrievers.tf_vector")
|
|
111
|
+
|
|
112
|
+
notes = FilesystemCorpus.Corpus {
|
|
113
|
+
root = "corpora/notes",
|
|
114
|
+
configuration = {
|
|
115
|
+
pipeline = {
|
|
116
|
+
extract = {
|
|
117
|
+
-- extraction steps (optional)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
search = vector.Retriever {
|
|
124
|
+
corpus = notes,
|
|
125
|
+
configuration = {
|
|
126
|
+
pipeline = {
|
|
127
|
+
index = {
|
|
128
|
+
-- optional index settings
|
|
129
|
+
},
|
|
130
|
+
query = {
|
|
131
|
+
limit = 2,
|
|
132
|
+
maximum_total_characters = 1200
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
local embedding_index_file = require("tactus.retrievers.embedding_index_file")
|
|
2
|
+
local embedding_index_inmemory = require("tactus.retrievers.embedding_index_inmemory")
|
|
3
|
+
local sqlite_full_text_search = require("tactus.retrievers.sqlite_full_text_search")
|
|
4
|
+
local tf_vector = require("tactus.retrievers.tf_vector")
|
|
5
|
+
|
|
6
|
+
return {
|
|
7
|
+
EmbeddingIndexFile = embedding_index_file,
|
|
8
|
+
EmbeddingIndexInMemory = embedding_index_inmemory,
|
|
9
|
+
SqliteFullTextSearch = sqlite_full_text_search,
|
|
10
|
+
TfVector = tf_vector,
|
|
11
|
+
}
|
|
@@ -413,6 +413,7 @@ class BehaveEnvironmentGenerator:
|
|
|
413
413
|
f.write('"""\n\n')
|
|
414
414
|
|
|
415
415
|
f.write("import sys\n")
|
|
416
|
+
f.write("import os\n")
|
|
416
417
|
f.write("import json\n")
|
|
417
418
|
f.write("from pathlib import Path\n\n")
|
|
418
419
|
|
|
@@ -440,6 +441,7 @@ class BehaveEnvironmentGenerator:
|
|
|
440
441
|
f.write(f" context.mcp_servers = json.loads('{mcp_servers_json}')\n")
|
|
441
442
|
f.write(f" context.tool_paths = json.loads('{tool_paths_json}')\n")
|
|
442
443
|
f.write(f" context.mocked = {mocked}\n\n")
|
|
444
|
+
f.write(" os.environ['TACTUS_MOCK_MODE'] = '1' if context.mocked else '0'\n\n")
|
|
443
445
|
|
|
444
446
|
f.write("def before_scenario(context, scenario):\n")
|
|
445
447
|
f.write(' """Setup before each scenario."""\n')
|
tactus/testing/context.py
CHANGED
|
@@ -171,6 +171,7 @@ class TactusTestContext:
|
|
|
171
171
|
from tactus.testing.mock_registry import UnifiedMockRegistry
|
|
172
172
|
from tactus.adapters.cli_log import CLILogHandler
|
|
173
173
|
|
|
174
|
+
os.environ["TACTUS_MOCK_MODE"] = "1" if self.mocked else "0"
|
|
174
175
|
storage = MemoryStorage()
|
|
175
176
|
|
|
176
177
|
# Setup mock registry if in mocked mode
|
|
@@ -209,6 +210,9 @@ class TactusTestContext:
|
|
|
209
210
|
from tactus.core.mocking import MockManager
|
|
210
211
|
|
|
211
212
|
self.runtime.mock_manager = MockManager()
|
|
213
|
+
from tactus.core.mocking import set_current_mock_manager
|
|
214
|
+
|
|
215
|
+
set_current_mock_manager(self.runtime.mock_manager)
|
|
212
216
|
logger.info("Created MockManager for Mocks {} block support")
|
|
213
217
|
# Mocked-mode tests should never call real LLMs by default.
|
|
214
218
|
self.runtime.mock_all_agents = True
|