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.
Files changed (48) hide show
  1. tactus/__init__.py +1 -1
  2. tactus/adapters/channels/base.py +2 -0
  3. tactus/cli/app.py +212 -57
  4. tactus/core/compaction.py +17 -0
  5. tactus/core/context_assembler.py +73 -0
  6. tactus/core/context_models.py +41 -0
  7. tactus/core/dsl_stubs.py +568 -17
  8. tactus/core/exceptions.py +8 -0
  9. tactus/core/execution_context.py +1 -1
  10. tactus/core/mocking.py +12 -0
  11. tactus/core/registry.py +142 -0
  12. tactus/core/retrieval.py +317 -0
  13. tactus/core/retriever_tasks.py +30 -0
  14. tactus/core/runtime.py +441 -75
  15. tactus/dspy/agent.py +143 -82
  16. tactus/dspy/config.py +16 -0
  17. tactus/dspy/module.py +12 -1
  18. tactus/ide/coding_assistant.py +2 -2
  19. tactus/plugins/__init__.py +3 -0
  20. tactus/plugins/noaa.py +76 -0
  21. tactus/primitives/handles.py +79 -7
  22. tactus/sandbox/config.py +1 -1
  23. tactus/sandbox/container_runner.py +2 -0
  24. tactus/sandbox/entrypoint.py +51 -8
  25. tactus/sandbox/protocol.py +5 -0
  26. tactus/stdlib/README.md +10 -1
  27. tactus/stdlib/biblicus/__init__.py +3 -0
  28. tactus/stdlib/biblicus/text.py +208 -0
  29. tactus/stdlib/tac/biblicus/text.tac +32 -0
  30. tactus/stdlib/tac/tactus/biblicus.spec.tac +179 -0
  31. tactus/stdlib/tac/tactus/corpora/base.tac +42 -0
  32. tactus/stdlib/tac/tactus/corpora/filesystem.tac +5 -0
  33. tactus/stdlib/tac/tactus/retrievers/base.tac +37 -0
  34. tactus/stdlib/tac/tactus/retrievers/embedding_index_file.tac +6 -0
  35. tactus/stdlib/tac/tactus/retrievers/embedding_index_inmemory.tac +6 -0
  36. tactus/stdlib/tac/tactus/retrievers/index.md +137 -0
  37. tactus/stdlib/tac/tactus/retrievers/init.tac +11 -0
  38. tactus/stdlib/tac/tactus/retrievers/sqlite_full_text_search.tac +6 -0
  39. tactus/stdlib/tac/tactus/retrievers/tf_vector.tac +6 -0
  40. tactus/testing/behave_integration.py +2 -0
  41. tactus/testing/context.py +4 -0
  42. tactus/validation/semantic_visitor.py +430 -88
  43. tactus/validation/validator.py +142 -2
  44. {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/METADATA +3 -2
  45. {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/RECORD +48 -28
  46. {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/WHEEL +0 -0
  47. {tactus-0.37.0.dist-info → tactus-0.39.0.dist-info}/entry_points.txt +0 -0
  48. {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,5 @@
1
+ local base = require("tactus.corpora.base")
2
+
3
+ return {
4
+ Corpus = base.wrap_corpus({}),
5
+ }
@@ -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,6 @@
1
+ local base = require("tactus.retrievers.base")
2
+
3
+ return {
4
+ Corpus = base.wrap_corpus({}),
5
+ Retriever = base.wrap_retriever({ retriever_id = "embedding-index-file" }),
6
+ }
@@ -0,0 +1,6 @@
1
+ local base = require("tactus.retrievers.base")
2
+
3
+ return {
4
+ Corpus = base.wrap_corpus({}),
5
+ Retriever = base.wrap_retriever({ retriever_id = "embedding-index-inmemory" }),
6
+ }
@@ -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
+ }
@@ -0,0 +1,6 @@
1
+ local base = require("tactus.retrievers.base")
2
+
3
+ return {
4
+ Corpus = base.wrap_corpus({}),
5
+ Retriever = base.wrap_retriever({ retriever_id = "sqlite-full-text-search" }),
6
+ }
@@ -0,0 +1,6 @@
1
+ local base = require("tactus.retrievers.base")
2
+
3
+ return {
4
+ Corpus = base.wrap_corpus({}),
5
+ Retriever = base.wrap_retriever({ retriever_id = "tf-vector" }),
6
+ }
@@ -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