tactus 0.31.1__py3-none-any.whl → 0.32.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 CHANGED
@@ -5,7 +5,7 @@ Tactus provides a declarative workflow engine for AI agents with pluggable
5
5
  backends for storage, HITL, and chat recording.
6
6
  """
7
7
 
8
- __version__ = "0.31.1"
8
+ __version__ = "0.32.0"
9
9
 
10
10
  # Core exports
11
11
  from tactus.core.runtime import TactusRuntime
tactus/dspy/agent.py CHANGED
@@ -599,6 +599,27 @@ class DSPyAgentHandle:
599
599
 
600
600
  # Check for errors
601
601
  if result_holder["error"] is not None:
602
+ error = result_holder["error"]
603
+
604
+ # Unwrap ExceptionGroup to find the real error
605
+ original_error = error
606
+ if hasattr(error, "__class__") and error.__class__.__name__ == "ExceptionGroup":
607
+ # Python 3.11+ ExceptionGroup
608
+ if hasattr(error, "exceptions") and error.exceptions:
609
+ original_error = error.exceptions[0]
610
+
611
+ # Check if it's an authentication error (in original or wrapped)
612
+ error_str = str(original_error).lower()
613
+ error_type = str(type(original_error).__name__)
614
+
615
+ if "authenticationerror" in error_type.lower() or "api_key" in error_str:
616
+ from tactus.core.exceptions import TactusRuntimeError
617
+
618
+ raise TactusRuntimeError(
619
+ f"API authentication failed for agent '{self.name}': "
620
+ f"Missing or invalid API key. Please configure your API key in Settings (Cmd+,)."
621
+ ) from error
622
+
602
623
  raise result_holder["error"]
603
624
 
604
625
  # If streaming failed to produce a result, fall back to non-streaming
@@ -0,0 +1,536 @@
1
+ """
2
+ Configuration API endpoints for Tactus IDE.
3
+
4
+ Provides RESTful API for loading and saving configuration files,
5
+ with support for the configuration cascade system.
6
+ """
7
+
8
+ import logging
9
+ import shutil
10
+ import yaml
11
+ from pathlib import Path
12
+ from flask import Blueprint, request, jsonify
13
+ from typing import Dict, Any, List, Tuple, Optional
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ config_bp = Blueprint("config", __name__, url_prefix="/api/config")
18
+
19
+
20
+ def build_cascade_map(loaded_configs: List[Tuple[str, Dict[str, Any]]]) -> Dict[str, str]:
21
+ """
22
+ Build a map of config path -> source for cascade visualization.
23
+
24
+ Args:
25
+ loaded_configs: List of (source_name, config_dict) tuples
26
+
27
+ Returns:
28
+ Dictionary mapping config paths to their source
29
+ """
30
+ cascade_map = {}
31
+
32
+ def add_paths(obj: Any, prefix: str = "", source: str = ""):
33
+ """Recursively add paths from nested config structure."""
34
+ if isinstance(obj, dict):
35
+ for key, value in obj.items():
36
+ path = f"{prefix}.{key}" if prefix else key
37
+ cascade_map[path] = source
38
+ add_paths(value, path, source)
39
+ elif isinstance(obj, list):
40
+ for i, item in enumerate(obj):
41
+ path = f"{prefix}[{i}]"
42
+ add_paths(item, path, source)
43
+
44
+ # Process configs in order (later ones override)
45
+ for source, config in loaded_configs:
46
+ # Extract simple source name (e.g., "user" from "user:/path/to/config.yml")
47
+ source_name = source.split(":")[0] if ":" in source else source
48
+ add_paths(config, "", source_name)
49
+
50
+ return cascade_map
51
+
52
+
53
+ def load_yaml_file(path: Path) -> Optional[Dict[str, Any]]:
54
+ """
55
+ Load YAML file safely.
56
+
57
+ Args:
58
+ path: Path to YAML file
59
+
60
+ Returns:
61
+ Configuration dictionary or None if file doesn't exist or fails to load
62
+ """
63
+ if not path.exists():
64
+ return None
65
+
66
+ try:
67
+ with open(path, "r") as f:
68
+ config = yaml.safe_load(f)
69
+ return config if isinstance(config, dict) else {}
70
+ except Exception as e:
71
+ logger.warning(f"Failed to load config from {path}: {e}")
72
+ return None
73
+
74
+
75
+ def save_yaml_file(path: Path, config: Dict[str, Any], create_backup: bool = True):
76
+ """
77
+ Save configuration to YAML file.
78
+
79
+ Args:
80
+ path: Path to save config
81
+ config: Configuration dictionary
82
+ create_backup: Whether to create backup of existing file
83
+ """
84
+ # Create .tactus directory if needed
85
+ path.parent.mkdir(parents=True, exist_ok=True)
86
+
87
+ # Create backup if requested and file exists
88
+ if create_backup and path.exists():
89
+ backup_path = path.with_suffix(".yml.bak")
90
+ shutil.copy2(path, backup_path)
91
+ logger.info(f"Created backup: {backup_path}")
92
+
93
+ # Save config
94
+ with open(path, "w") as f:
95
+ yaml.safe_dump(
96
+ config,
97
+ f,
98
+ default_flow_style=False,
99
+ sort_keys=False,
100
+ allow_unicode=True,
101
+ indent=2,
102
+ )
103
+
104
+ logger.info(f"Saved config to: {path}")
105
+
106
+
107
+ @config_bp.route("", methods=["GET"])
108
+ def get_config():
109
+ """
110
+ Get configuration with cascade information.
111
+
112
+ Returns:
113
+ JSON response with:
114
+ - config: Merged effective configuration
115
+ - project_config: Project .tactus/config.yml
116
+ - user_config: User ~/.tactus/config.yml
117
+ - system_config: System config if exists
118
+ - cascade: Map of config paths to their source (legacy)
119
+ - source_details: Detailed source tracking with override chains
120
+ - writable_configs: Which configs can be edited
121
+ - config_paths: Full paths to all config files
122
+ """
123
+ try:
124
+ from tactus.core.config_manager import ConfigManager
125
+
126
+ # Create config manager
127
+ config_manager = ConfigManager()
128
+
129
+ # For IDE purposes, we load config without a specific procedure
130
+ # Use a dummy path to trigger the cascade from project/user/system
131
+ dummy_path = Path.cwd() / "dummy.tac"
132
+
133
+ # Load cascade with source tracking
134
+ effective_config, source_map = config_manager.load_cascade_with_sources(dummy_path)
135
+
136
+ # Build legacy cascade map from loaded configs (for backward compatibility)
137
+ cascade_map = build_cascade_map(config_manager.loaded_configs)
138
+
139
+ # Convert source_map to JSON-serializable format
140
+ source_details = {path: config_value.to_dict() for path, config_value in source_map.items()}
141
+
142
+ # Load individual config files for editing
143
+ project_config_path = Path.cwd() / ".tactus" / "config.yml"
144
+ project_config = load_yaml_file(project_config_path)
145
+
146
+ # Check if we should initialize from example template
147
+ # This happens when:
148
+ # 1. No config.yml exists, OR
149
+ # 2. Config exists but has no API keys configured (openai_api_key is empty/missing)
150
+ should_initialize_from_example = False
151
+
152
+ if project_config is None:
153
+ should_initialize_from_example = True
154
+ elif isinstance(project_config, dict):
155
+ # Check if API keys are configured
156
+ # Support both old flat format (openai_api_key) and new nested format (openai.api_key)
157
+ openai_key = None
158
+ if "openai" in project_config and isinstance(project_config["openai"], dict):
159
+ openai_key = project_config["openai"].get("api_key")
160
+ else:
161
+ openai_key = project_config.get("openai_api_key")
162
+
163
+ aws_key = None
164
+ if "aws" in project_config and isinstance(project_config["aws"], dict):
165
+ aws_key = project_config["aws"].get("profile") or project_config["aws"].get(
166
+ "access_key_id"
167
+ )
168
+ else:
169
+ aws_key = project_config.get("aws_access_key_id")
170
+
171
+ google_key = None
172
+ if "google" in project_config and isinstance(project_config["google"], dict):
173
+ google_key = project_config["google"].get("api_key")
174
+
175
+ # Check if keys are present and not placeholder values
176
+ # Empty strings or None mean not configured
177
+ has_openai_key = (
178
+ openai_key
179
+ and str(openai_key).strip() != ""
180
+ and not str(openai_key).startswith("your-")
181
+ )
182
+ has_aws_keys = (
183
+ aws_key
184
+ and str(aws_key).strip() != ""
185
+ and str(aws_key) != "default"
186
+ and not str(aws_key).startswith("your-")
187
+ )
188
+ has_google_key = (
189
+ google_key
190
+ and str(google_key).strip() != ""
191
+ and not str(google_key).startswith("your-")
192
+ )
193
+
194
+ # If no API keys are configured, initialize from example
195
+ if not has_openai_key and not has_aws_keys and not has_google_key:
196
+ should_initialize_from_example = True
197
+ else:
198
+ project_config = {}
199
+
200
+ if should_initialize_from_example:
201
+ example_config_path = Path.cwd() / ".tactus" / "config.yml.example"
202
+ if example_config_path.exists():
203
+ example_config = load_yaml_file(example_config_path) or {}
204
+ # Merge with existing config (keeps existing values, adds missing fields from example)
205
+ if project_config and isinstance(project_config, dict):
206
+ # Deep merge: example provides defaults, existing values are kept
207
+ merged_config = {**example_config, **project_config}
208
+ else:
209
+ merged_config = example_config
210
+ project_config = merged_config
211
+ # Save the merged config
212
+ try:
213
+ save_yaml_file(project_config_path, project_config, create_backup=True)
214
+ logger.info(
215
+ f"Initialized/merged config with example template: {example_config_path}"
216
+ )
217
+ except Exception as e:
218
+ logger.warning(f"Failed to save merged config: {e}")
219
+ elif not project_config:
220
+ # No example found and no existing config, use empty
221
+ project_config = {}
222
+
223
+ user_config_path = Path.home() / ".tactus" / "config.yml"
224
+ user_config = load_yaml_file(user_config_path) or {}
225
+
226
+ # Try to find system config
227
+ system_config_path = Path("/etc/tactus/config.yml")
228
+ system_config = load_yaml_file(system_config_path) or {}
229
+
230
+ # Determine which configs are writable
231
+ writable_configs = {
232
+ "system": False, # System config is never writable from IDE
233
+ "user": user_config_path.parent.exists() or True, # Can create user config
234
+ "project": True, # Can always write to project config
235
+ }
236
+
237
+ return jsonify(
238
+ {
239
+ "config": effective_config,
240
+ "project_config": project_config,
241
+ "user_config": user_config,
242
+ "system_config": system_config,
243
+ "cascade": cascade_map,
244
+ "source_details": source_details,
245
+ "writable_configs": writable_configs,
246
+ "config_paths": {
247
+ "system": str(system_config_path),
248
+ "user": str(user_config_path),
249
+ "project": str(project_config_path),
250
+ },
251
+ # Keep old fields for backward compatibility
252
+ "project_config_path": str(project_config_path),
253
+ "user_config_path": str(user_config_path),
254
+ }
255
+ )
256
+
257
+ except Exception as e:
258
+ logger.error(f"Error loading config: {e}", exc_info=True)
259
+ return jsonify({"error": str(e)}), 500
260
+
261
+
262
+ @config_bp.route("", methods=["POST"])
263
+ def save_config():
264
+ """
265
+ Save configuration to specified target file.
266
+
267
+ Request body:
268
+ {
269
+ "config": {...},
270
+ "targetFile": "project" | "user",
271
+ "createBackup": true
272
+ }
273
+
274
+ Returns:
275
+ JSON response with success status and saved path
276
+ """
277
+ try:
278
+ data = request.json
279
+
280
+ if not data:
281
+ return jsonify({"error": "Missing request body"}), 400
282
+
283
+ config = data.get("config")
284
+ target = data.get("targetFile", "project")
285
+ create_backup = data.get("createBackup", True)
286
+
287
+ if not config:
288
+ return jsonify({"error": "Missing config"}), 400
289
+
290
+ if not isinstance(config, dict):
291
+ return jsonify({"error": "Config must be an object"}), 400
292
+
293
+ # Determine target path
294
+ if target == "project":
295
+ config_path = Path.cwd() / ".tactus" / "config.yml"
296
+ elif target == "user":
297
+ config_path = Path.home() / ".tactus" / "config.yml"
298
+ else:
299
+ return jsonify({"error": f"Invalid target: {target}"}), 400
300
+
301
+ # Save config
302
+ save_yaml_file(config_path, config, create_backup)
303
+
304
+ # Trigger a runtime reload by emitting an event or clearing caches
305
+ # This ensures the new config is picked up without requiring a restart
306
+ try:
307
+ from tactus.ide.server import clear_runtime_caches
308
+
309
+ clear_runtime_caches()
310
+ logger.info("Cleared runtime caches after config save")
311
+ except (ImportError, AttributeError):
312
+ # If function doesn't exist yet, that's okay - just log it
313
+ logger.debug("Runtime cache clearing not available")
314
+
315
+ return jsonify({"success": True, "path": str(config_path)})
316
+
317
+ except Exception as e:
318
+ logger.error(f"Error saving config: {e}", exc_info=True)
319
+ return jsonify({"error": str(e)}), 500
320
+
321
+
322
+ @config_bp.route("/save-by-source", methods=["POST"])
323
+ def save_config_by_source():
324
+ """
325
+ Save configuration changes to the appropriate file based on source tracking.
326
+
327
+ This endpoint intelligently routes config changes to the correct file based on
328
+ where each value is currently sourced from, or uses a fallback strategy.
329
+
330
+ Request body:
331
+ {
332
+ "changes": {
333
+ "aws.region": "us-west-2",
334
+ "default_model": "gpt-4o"
335
+ },
336
+ "target_strategy": "source_aware" | "force_user" | "force_project"
337
+ }
338
+
339
+ Returns:
340
+ JSON response with:
341
+ - success: Boolean
342
+ - saved_to: Dict mapping change paths to files they were saved to
343
+ - errors: List of any errors (e.g., trying to override env var)
344
+ """
345
+ try:
346
+ from tactus.core.config_manager import ConfigManager
347
+
348
+ data = request.json
349
+
350
+ if not data:
351
+ return jsonify({"error": "Missing request body"}), 400
352
+
353
+ changes = data.get("changes")
354
+ strategy = data.get("target_strategy", "source_aware")
355
+
356
+ if not changes:
357
+ return jsonify({"error": "Missing changes"}), 400
358
+
359
+ if not isinstance(changes, dict):
360
+ return jsonify({"error": "Changes must be an object"}), 400
361
+
362
+ # Load current config with sources
363
+ config_manager = ConfigManager()
364
+ dummy_path = Path.cwd() / "dummy.tac"
365
+ effective_config, source_map = config_manager.load_cascade_with_sources(dummy_path)
366
+
367
+ # Load current project and user configs
368
+ project_config_path = Path.cwd() / ".tactus" / "config.yml"
369
+ project_config = load_yaml_file(project_config_path) or {}
370
+
371
+ user_config_path = Path.home() / ".tactus" / "config.yml"
372
+ user_config = load_yaml_file(user_config_path) or {}
373
+
374
+ saved_to = {}
375
+ errors = []
376
+
377
+ # Process each change
378
+ for path, new_value in changes.items():
379
+ # Determine target file based on strategy
380
+ if strategy == "force_user":
381
+ target_file = "user"
382
+ target_config = user_config
383
+ elif strategy == "force_project":
384
+ target_file = "project"
385
+ target_config = project_config
386
+ else: # source_aware
387
+ # Check current source
388
+ if path in source_map:
389
+ source_info = source_map[path]
390
+
391
+ # Check if sourced from environment variable
392
+ if source_info.is_env_override:
393
+ errors.append(
394
+ f"{path}: Cannot override environment variable "
395
+ f"{source_info.original_env_var} in config file"
396
+ )
397
+ continue
398
+
399
+ # Route to the source file
400
+ if source_info.source_type == "user":
401
+ target_file = "user"
402
+ target_config = user_config
403
+ elif source_info.source_type == "project":
404
+ target_file = "project"
405
+ target_config = project_config
406
+ else:
407
+ # For system or other sources, default to user config
408
+ target_file = "user"
409
+ target_config = user_config
410
+ else:
411
+ # New value, default to user config
412
+ target_file = "user"
413
+ target_config = user_config
414
+
415
+ # Update the target config dict
416
+ _set_nested_value(target_config, path, new_value)
417
+ saved_to[path] = target_file
418
+
419
+ # Save modified configs
420
+ if any(v == "user" for v in saved_to.values()):
421
+ save_yaml_file(user_config_path, user_config, create_backup=True)
422
+
423
+ if any(v == "project" for v in saved_to.values()):
424
+ save_yaml_file(project_config_path, project_config, create_backup=True)
425
+
426
+ return jsonify(
427
+ {
428
+ "success": len(errors) == 0,
429
+ "saved_to": saved_to,
430
+ "errors": errors,
431
+ }
432
+ )
433
+
434
+ except Exception as e:
435
+ logger.error(f"Error saving config by source: {e}", exc_info=True)
436
+ return jsonify({"error": str(e)}), 500
437
+
438
+
439
+ def _set_nested_value(config: Dict[str, Any], path: str, value: Any) -> None:
440
+ """
441
+ Set a nested value in a config dict using dot notation path.
442
+
443
+ Args:
444
+ config: Configuration dictionary to modify
445
+ path: Dot-separated path (e.g., "aws.region")
446
+ value: Value to set
447
+ """
448
+ keys = path.split(".")
449
+ current = config
450
+
451
+ # Navigate to the parent of the target key
452
+ for key in keys[:-1]:
453
+ if key not in current:
454
+ current[key] = {}
455
+ elif not isinstance(current[key], dict):
456
+ # Path conflicts with existing non-dict value
457
+ raise ValueError(f"Cannot set nested value: {key} is not a dict")
458
+ current = current[key]
459
+
460
+ # Set the final value
461
+ current[keys[-1]] = value
462
+
463
+
464
+ @config_bp.route("/validate", methods=["POST"])
465
+ def validate_config():
466
+ """
467
+ Validate configuration structure without saving.
468
+
469
+ Request body:
470
+ {
471
+ "config": {...}
472
+ }
473
+
474
+ Returns:
475
+ JSON response with validation results
476
+ """
477
+ try:
478
+ data = request.json
479
+
480
+ if not data:
481
+ return jsonify({"error": "Missing request body"}), 400
482
+
483
+ config = data.get("config")
484
+
485
+ if not config:
486
+ return jsonify({"error": "Missing config"}), 400
487
+
488
+ errors = []
489
+ warnings = []
490
+
491
+ # Basic validation
492
+ if not isinstance(config, dict):
493
+ errors.append("Config must be an object")
494
+ return jsonify({"valid": False, "errors": errors, "warnings": warnings})
495
+
496
+ # Validate known structure (optional - can be expanded)
497
+ # Check for common mistakes
498
+ if "default_provider" in config:
499
+ if config["default_provider"] not in ["openai", "bedrock", "google"]:
500
+ warnings.append(
501
+ f"Unknown provider: {config['default_provider']}. Expected openai, bedrock, or google."
502
+ )
503
+
504
+ if "ide" in config:
505
+ ide_config = config["ide"]
506
+ if not isinstance(ide_config, dict):
507
+ errors.append("ide config must be an object")
508
+
509
+ # Try to serialize to YAML (validation)
510
+ try:
511
+ yaml.safe_dump(config)
512
+ except Exception as e:
513
+ errors.append(f"Config cannot be serialized to YAML: {str(e)}")
514
+
515
+ return jsonify(
516
+ {
517
+ "valid": len(errors) == 0,
518
+ "errors": errors,
519
+ "warnings": warnings,
520
+ }
521
+ )
522
+
523
+ except Exception as e:
524
+ logger.error(f"Error validating config: {e}", exc_info=True)
525
+ return jsonify({"error": str(e)}), 500
526
+
527
+
528
+ def register_config_routes(app):
529
+ """
530
+ Register config routes with Flask app.
531
+
532
+ Args:
533
+ app: Flask application instance
534
+ """
535
+ app.register_blueprint(config_bp)
536
+ logger.info("Registered config API routes")
tactus/ide/server.py CHANGED
@@ -25,6 +25,17 @@ logger = logging.getLogger(__name__)
25
25
  # Workspace state
26
26
  WORKSPACE_ROOT = None
27
27
 
28
+ # Global cache clearing function - set by create_app()
29
+ _clear_runtime_caches_fn = None
30
+
31
+
32
+ def clear_runtime_caches():
33
+ """Clear cached runtime instances. Must be called after create_app() initializes."""
34
+ if _clear_runtime_caches_fn:
35
+ _clear_runtime_caches_fn()
36
+ else:
37
+ logger.warning("clear_runtime_caches called but no implementation set")
38
+
28
39
 
29
40
  class TactusLSPHandler:
30
41
  """LSP handler for Tactus DSL."""
@@ -743,7 +754,23 @@ def create_app(initial_workspace: Optional[str] = None, frontend_dist_dir: Optio
743
754
  )
744
755
  storage_backend = FileStorage(storage_dir=storage_dir)
745
756
 
746
- # Create runtime with log handler and run_id
757
+ # Load configuration cascade for this procedure
758
+ from tactus.core.config_manager import ConfigManager
759
+
760
+ config_manager = ConfigManager()
761
+ merged_config = config_manager.load_cascade(path)
762
+
763
+ # Extract API keys and other config values
764
+ openai_api_key = (
765
+ merged_config.get("openai", {}).get("api_key")
766
+ if isinstance(merged_config.get("openai"), dict)
767
+ else merged_config.get("openai_api_key")
768
+ ) or os.environ.get("OPENAI_API_KEY")
769
+
770
+ tool_paths = merged_config.get("tool_paths")
771
+ mcp_servers = merged_config.get("mcp_servers", {})
772
+
773
+ # Create runtime with log handler, run_id, and loaded config
747
774
  runtime = TactusRuntime(
748
775
  procedure_id=procedure_id,
749
776
  storage_backend=storage_backend,
@@ -751,6 +778,10 @@ def create_app(initial_workspace: Optional[str] = None, frontend_dist_dir: Optio
751
778
  log_handler=log_handler,
752
779
  run_id=run_id,
753
780
  source_file_path=str(path),
781
+ openai_api_key=openai_api_key,
782
+ tool_paths=tool_paths,
783
+ mcp_servers=mcp_servers,
784
+ external_config=merged_config,
754
785
  )
755
786
 
756
787
  # Read procedure source
@@ -1940,6 +1971,17 @@ def create_app(initial_workspace: Optional[str] = None, frontend_dist_dir: Optio
1940
1971
  raise
1941
1972
  return coding_assistant
1942
1973
 
1974
+ def _clear_caches_impl():
1975
+ """Clear cached runtime instances (e.g., after config changes)."""
1976
+ nonlocal coding_assistant
1977
+ if coding_assistant is not None:
1978
+ logger.info("Clearing coding assistant cache")
1979
+ coding_assistant = None
1980
+
1981
+ # Set the global cache clearing function
1982
+ global _clear_runtime_caches_fn
1983
+ _clear_runtime_caches_fn = _clear_caches_impl
1984
+
1943
1985
  @app.route("/api/chat", methods=["POST"])
1944
1986
  def chat_message():
1945
1987
  """Handle chat messages from the user."""
@@ -2147,18 +2189,9 @@ def create_app(initial_workspace: Optional[str] = None, frontend_dist_dir: Optio
2147
2189
 
2148
2190
  # Register config API routes
2149
2191
  try:
2150
- import sys
2151
-
2152
- # Add tactus-ide/backend to path for imports
2153
- # Path from tactus/ide/server.py -> project root -> tactus-ide/backend
2154
- backend_dir = Path(__file__).parent.parent.parent / "tactus-ide" / "backend"
2155
- if backend_dir.exists():
2156
- sys.path.insert(0, str(backend_dir))
2157
- from config_server import register_config_routes
2192
+ from tactus.ide.config_server import register_config_routes
2158
2193
 
2159
- register_config_routes(app)
2160
- else:
2161
- logger.warning(f"Config server backend directory not found: {backend_dir}")
2194
+ register_config_routes(app)
2162
2195
  except ImportError as e:
2163
2196
  logger.warning(f"Could not register config routes: {e}")
2164
2197
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tactus
3
- Version: 0.31.1
3
+ Version: 0.32.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
@@ -1,4 +1,4 @@
1
- tactus/__init__.py,sha256=BJ9CdK9Kx8CsGYAjjINCza1im3hMyVnvuSS05wTE1O0,1245
1
+ tactus/__init__.py,sha256=wtetcKPW4NNehgtbAv95KoUrOg_ddNUi6VEYMuINON4,1245
2
2
  tactus/adapters/__init__.py,sha256=lU8uUxuryFRIpVrn_KeVK7aUhsvOT1tYsuE3FOOIFpI,289
3
3
  tactus/adapters/broker_log.py,sha256=mIjARt1Q6ouWVbVri6zep1e8tzm9y28l4WOEdqiK39Q,2849
4
4
  tactus/adapters/cli_hitl.py,sha256=3dH58du0lN4k-OvQrAHrAqHFqBjolqNKFb94JaNHtn8,6964
@@ -41,7 +41,7 @@ tactus/core/dependencies/registry.py,sha256=bgRdqJJTUrnQlu0wvjv2In1EPq7prZq-b9eB
41
41
  tactus/docker/Dockerfile,sha256=fnK5kZlgM-L7vboiwfTqcs70OsZsvh1ba4YzRxie138,1887
42
42
  tactus/docker/entrypoint.sh,sha256=pL-1MwMdjD1fGgRZYkBeXmJZg57Knmub9ETLYAANvOg,1985
43
43
  tactus/dspy/__init__.py,sha256=beUkvMUFdPvZE9-bEOfRo2TH-FoCvPT_L9_dpJPW324,1226
44
- tactus/dspy/agent.py,sha256=d1Zpg7OUZcRIkHmlbtlgB5N81z0vLhadNloFL73yEpg,45625
44
+ tactus/dspy/agent.py,sha256=W-xe0l3simfrQHT3N3Y5Rtofu7PKpNvYGQyVGaJXXGs,46626
45
45
  tactus/dspy/broker_lm.py,sha256=EaXlJcUhfM0NV0fD1rASYKSO5gm846KRS5BoT0iO4zs,6239
46
46
  tactus/dspy/config.py,sha256=B22ON9Zp-dabI4NYeMbZ5lUL4kqihR7FQ8Z8xKT_eL8,6567
47
47
  tactus/dspy/history.py,sha256=0yGi3P5ruRUPoRyaCWsUDeuEYYsfproc_7pMVZuhmUo,5980
@@ -52,7 +52,8 @@ tactus/formatting/__init__.py,sha256=pkwfAJwMxdRha2oahXoUrVjk6if7QH5d1U5t5dF2fXc
52
52
  tactus/formatting/formatter.py,sha256=DfHp977t5reMPIWZwRChRE5Yflw7xGgTNUM0AOcS8LQ,14510
53
53
  tactus/ide/__init__.py,sha256=1fSC0xWP-Lq5wl4FgDq7SMnkvZ0DxXupreTl3ZRX1zw,143
54
54
  tactus/ide/coding_assistant.py,sha256=GgmspWIn9IPgBK0ZYapeISIOrcDfRyK7yyPDPV85r8g,12184
55
- tactus/ide/server.py,sha256=4E5Sc3Qf0WYbWjxwNUIK4somjp4a7i_CNpBsj3Bi8GM,94089
55
+ tactus/ide/config_server.py,sha256=U8OWxi5l24GH1lUHIAQ8WB8j0cJ5ofLX9iVecW1O2vc,18862
56
+ tactus/ide/server.py,sha256=9hn65ZsNTCQ3rboUvPZD1LFMPmeaezyhxAhw0o4bhfc,95439
56
57
  tactus/primitives/__init__.py,sha256=x6bGwoa9DizKUwqsg7SqURfJxisEdctTCv1XnSAZxIk,1709
57
58
  tactus/primitives/control.py,sha256=PjRt_Pegcj2L1Uy-IUBQKTYFRMXy7b9q1z2kzJNH8qw,4683
58
59
  tactus/primitives/file.py,sha256=-kz0RCst_i_3V860-LtGntYpE0Mm371U_KGHqELbMx0,7186
@@ -153,8 +154,8 @@ tactus/validation/generated/LuaParserVisitor.py,sha256=ageKSmHPxnO3jBS2fBtkmYBOd
153
154
  tactus/validation/generated/__init__.py,sha256=5gWlwRI0UvmHw2fnBpj_IG6N8oZeabr5tbj1AODDvjc,196
154
155
  tactus/validation/grammar/LuaLexer.g4,sha256=t2MXiTCr127RWAyQGvamkcU_m4veqPzSuHUtAKwalw4,2771
155
156
  tactus/validation/grammar/LuaParser.g4,sha256=ceZenb90BdiZmVdOxMGj9qJk3QbbWVZe5HUqPgoePfY,3202
156
- tactus-0.31.1.dist-info/METADATA,sha256=Rmp1DSHekY6Jzb_QBNWG6f-_mkLd8M_KqU4D6EUe6fA,58693
157
- tactus-0.31.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
158
- tactus-0.31.1.dist-info/entry_points.txt,sha256=vWseqty8m3z-Worje0IYxlioMjPDCoSsm0AtY4GghBY,47
159
- tactus-0.31.1.dist-info/licenses/LICENSE,sha256=ivohBcAIYnaLPQ-lKEeCXSMvQUVISpQfKyxHBHoa4GA,1066
160
- tactus-0.31.1.dist-info/RECORD,,
157
+ tactus-0.32.0.dist-info/METADATA,sha256=pfLkzeGm-1UMToOvNJU1YrhJ87HDjiSeTApdHqqR5OA,58693
158
+ tactus-0.32.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
159
+ tactus-0.32.0.dist-info/entry_points.txt,sha256=vWseqty8m3z-Worje0IYxlioMjPDCoSsm0AtY4GghBY,47
160
+ tactus-0.32.0.dist-info/licenses/LICENSE,sha256=ivohBcAIYnaLPQ-lKEeCXSMvQUVISpQfKyxHBHoa4GA,1066
161
+ tactus-0.32.0.dist-info/RECORD,,