ct-toolkit 0.2.8__tar.gz → 0.2.9__tar.gz

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 (51) hide show
  1. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/PKG-INFO +1 -1
  2. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/core/wrapper.py +2 -0
  3. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/divergence/engine.py +4 -0
  4. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/divergence/l2_judge.py +20 -9
  5. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/divergence/l3_icm.py +18 -7
  6. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/identity/embedding.py +38 -22
  7. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit.egg-info/PKG-INFO +1 -1
  8. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/pyproject.toml +1 -1
  9. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/LICENSE +0 -0
  10. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/README.md +0 -0
  11. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/__init__.py +0 -0
  12. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/core/__init__.py +0 -0
  13. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/core/compatibility.py +0 -0
  14. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/core/exceptions.py +0 -0
  15. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/core/integrity.py +0 -0
  16. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/core/kernel.py +0 -0
  17. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/divergence/__init__.py +0 -0
  18. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/divergence/analysis.py +0 -0
  19. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/divergence/loss.py +0 -0
  20. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/divergence/scheduler.py +0 -0
  21. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/endorsement/__init__.py +0 -0
  22. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/endorsement/probes/__init__.py +0 -0
  23. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/endorsement/reflective.py +0 -0
  24. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/identity/__init__.py +0 -0
  25. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/identity/templates/__init__.py +0 -0
  26. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/identity/templates/defense.yaml +0 -0
  27. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/identity/templates/finance.yaml +0 -0
  28. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/identity/templates/general.yaml +0 -0
  29. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/identity/templates/medical.yaml +0 -0
  30. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/kernels/__init__.py +0 -0
  31. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/kernels/default.yaml +0 -0
  32. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/kernels/defense.yaml +0 -0
  33. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/middleware/__init__.py +0 -0
  34. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/middleware/autogen.py +0 -0
  35. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/middleware/crewai.py +0 -0
  36. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/middleware/deepagents.py +0 -0
  37. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/middleware/langchain.py +0 -0
  38. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/provenance/__init__.py +0 -0
  39. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/provenance/log.py +0 -0
  40. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/provenance/vault/__init__.py +0 -0
  41. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/utils/__init__.py +0 -0
  42. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit/utils/logger.py +0 -0
  43. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit.egg-info/SOURCES.txt +0 -0
  44. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit.egg-info/dependency_links.txt +0 -0
  45. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit.egg-info/requires.txt +0 -0
  46. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/ct_toolkit.egg-info/top_level.txt +0 -0
  47. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/setup.cfg +0 -0
  48. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/tests/test_analysis.py +0 -0
  49. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/tests/test_deep_agents_integration.py +0 -0
  50. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/tests/test_loss.py +0 -0
  51. {ct_toolkit-0.2.8 → ct_toolkit-0.2.9}/tests/test_summarization_drift.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ct-toolkit
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Computational Theseus Toolkit — Identity Continuity Guardrails for Agentic Systems
5
5
  Author: Hakan Damar
6
6
  License: Apache-2.0
@@ -304,6 +304,7 @@ class TheseusWrapper:
304
304
  template=self._config.template,
305
305
  embedding_client=emb_client,
306
306
  embedding_model=self._config.embedding_model,
307
+ project_root=self._project_root,
307
308
  )
308
309
 
309
310
  def _init_divergence_engine(self) -> Any:
@@ -335,6 +336,7 @@ class TheseusWrapper:
335
336
  l3_threshold=self._config.divergence_l3_threshold,
336
337
  enterprise_mode=self._config.enterprise_mode,
337
338
  scheduler=scheduler,
339
+ project_root=self._project_root,
338
340
  provenance_log=self._provenance_log,
339
341
  )
340
342
 
@@ -17,6 +17,7 @@ from __future__ import annotations
17
17
  import time
18
18
  from dataclasses import dataclass
19
19
  from enum import Enum
20
+ from pathlib import Path
20
21
  from typing import Any
21
22
 
22
23
  from ct_toolkit.identity.embedding import IdentityEmbeddingLayer
@@ -116,6 +117,7 @@ class DivergenceEngine:
116
117
  enterprise_mode: bool = False, # Run all tiers all the time
117
118
  scheduler: Any | None = None, # ElasticityScheduler instance
118
119
  provenance_log: Any | None = None,
120
+ project_root: Path | None = None,
119
121
  ) -> None:
120
122
  self._identity = identity_layer
121
123
  self._kernel = kernel
@@ -123,6 +125,7 @@ class DivergenceEngine:
123
125
  self._provider = provider
124
126
  self._judge_client = judge_client
125
127
  self._log = provenance_log
128
+ self._project_root = project_root
126
129
 
127
130
  # Base thresholds
128
131
  self._base_l1_threshold = l1_threshold
@@ -331,5 +334,6 @@ class DivergenceEngine:
331
334
  kernel=self._kernel,
332
335
  template=self._template,
333
336
  max_probes=max_probes,
337
+ project_root=self._project_root,
334
338
  )
335
339
  return runner.run()
@@ -139,15 +139,26 @@ class LLMJudge:
139
139
 
140
140
  try:
141
141
  # Call using instructor for structured data
142
- data: JudgeResponse = self._instructor_client.chat.completions.create(
143
- model=self._model,
144
- response_model=JudgeResponse,
145
- messages=[
146
- {"role": "system", "content": system_prompt},
147
- {"role": "user", "content": user_prompt},
148
- ],
149
- max_retries=2
150
- )
142
+ if self._provider == "anthropic":
143
+ data: JudgeResponse = self._instructor_client.messages.create(
144
+ model=self._model,
145
+ response_model=JudgeResponse,
146
+ system=system_prompt,
147
+ messages=[
148
+ {"role": "user", "content": user_prompt},
149
+ ],
150
+ max_retries=2
151
+ )
152
+ else:
153
+ data: JudgeResponse = self._instructor_client.chat.completions.create(
154
+ model=self._model,
155
+ response_model=JudgeResponse,
156
+ messages=[
157
+ {"role": "system", "content": system_prompt},
158
+ {"role": "user", "content": user_prompt},
159
+ ],
160
+ max_retries=2
161
+ )
151
162
 
152
163
  result = JudgeResult(
153
164
  verdict=data.verdict,
@@ -209,6 +209,7 @@ class ICMRunner:
209
209
  model: str | None = None,
210
210
  include_domain_probes: bool = True,
211
211
  max_probes: int | None = None,
212
+ project_root: Path | None = None,
212
213
  ) -> None:
213
214
  self._client = client
214
215
  self._provider = provider
@@ -216,6 +217,7 @@ class ICMRunner:
216
217
  self._template = template
217
218
  self._model = model or self._default_model(provider)
218
219
  self._include_domain = include_domain_probes
220
+ self._project_root = project_root
219
221
  self._max_probes = max_probes
220
222
 
221
223
  @staticmethod
@@ -332,13 +334,22 @@ class ICMRunner:
332
334
 
333
335
  # Domain probes — based on template
334
336
  if self._include_domain:
335
- domain_path = (
336
- self.PROBES_DIR / "domain_probes" / f"{self._template}_probes.json"
337
- )
338
- if domain_path.exists():
339
- with open(domain_path, encoding="utf-8") as f:
340
- probes.extend(json.load(f))
341
- logger.info(f"Domain probes loaded: {self._template}")
337
+ # Check user config first
338
+ domain_loaded = False
339
+ if self._project_root:
340
+ user_probe_path = self._project_root / "config" / f"{self._template}_probes.json"
341
+ if user_probe_path.exists():
342
+ with open(user_probe_path, encoding="utf-8") as f:
343
+ probes.extend(json.load(f))
344
+ logger.info(f"Custom domain probes loaded: {user_probe_path}")
345
+ domain_loaded = True
346
+
347
+ if not domain_loaded:
348
+ domain_path = self.PROBES_DIR / "domain_probes" / f"{self._template}_probes.json"
349
+ if domain_path.exists():
350
+ with open(domain_path, encoding="utf-8") as f:
351
+ probes.extend(json.load(f))
352
+ logger.info(f"Domain probes loaded: {self._template}")
342
353
 
343
354
  if not probes:
344
355
  logger.warning("Probe file not found. Empty battery.")
@@ -43,6 +43,7 @@ class IdentityEmbeddingLayer:
43
43
  template: str = "general",
44
44
  embedding_client: Any = None, # Provider client for real embeddings
45
45
  embedding_model: str = "text-embedding-3-small",
46
+ project_root: Path | None = None,
46
47
  ) -> None:
47
48
  self._template = template
48
49
  self._embedding_client = embedding_client
@@ -50,6 +51,7 @@ class IdentityEmbeddingLayer:
50
51
  self._reference_vector: np.ndarray | None = None
51
52
  self._template_keywords: list[str] = []
52
53
  self._reference_text: str = "" # stored for lazy computation
54
+ self._project_root = project_root
53
55
  self._embedding_method: str = "uninitialized"
54
56
  self._load_template()
55
57
 
@@ -58,34 +60,48 @@ class IdentityEmbeddingLayer:
58
60
  def _load_template(self) -> None:
59
61
  import os
60
62
  import yaml
61
- from importlib.resources import files
63
+
64
+ data = None
62
65
 
63
66
  # Sanitize template name to prevent path traversal
64
67
  safe_template = os.path.basename(self._template)
65
68
 
69
+ # 1. Check user config first if project_root is provided
70
+ if self._project_root:
71
+ # Check for both "name.yaml" and "name_identity.yaml"
72
+ for fname in [f"{safe_template}.yaml", f"{safe_template}_identity.yaml"]:
73
+ user_path = self._project_root / "config" / fname
74
+ if user_path.exists():
75
+ logger.debug(f"Loading identity template from user config: {user_path}")
76
+ with open(user_path, "r", encoding="utf-8") as f:
77
+ data = yaml.safe_load(f)
78
+ break
79
+
66
80
  # Load built-in template using importlib.resources
67
- try:
68
- template_resource = files("ct_toolkit.identity.templates").joinpath(f"{safe_template}.yaml")
69
- if template_resource.is_file():
70
- with template_resource.open("r", encoding="utf-8") as f:
71
- data = yaml.safe_load(f)
72
- else:
73
- raise FileNotFoundError(f"Template resource not found: {template_resource}")
74
- except (ImportError, FileNotFoundError):
75
- # Fallback for development or older environments
76
- template_path = (
77
- Path(__file__).parent
78
- / "templates"
79
- / f"{safe_template}.yaml"
80
- )
81
- if not template_path.exists():
82
- logger.warning(
83
- f"Template '{self._template}' not found, using 'general'."
81
+ if data is None:
82
+ try:
83
+ from importlib.resources import files
84
+ template_resource = files("ct_toolkit.identity.templates").joinpath(f"{safe_template}.yaml")
85
+ if template_resource.is_file():
86
+ with template_resource.open("r", encoding="utf-8") as f:
87
+ data = yaml.safe_load(f)
88
+ else:
89
+ raise FileNotFoundError(f"Template resource not found: {template_resource}")
90
+ except (ImportError, FileNotFoundError):
91
+ # Fallback for development or older environments
92
+ template_path = (
93
+ Path(__file__).parent
94
+ / "templates"
95
+ / f"{safe_template}.yaml"
84
96
  )
85
- template_path = Path(__file__).parent / "templates" / "general.yaml"
86
-
87
- with open(template_path, "r", encoding="utf-8") as f:
88
- data = yaml.safe_load(f)
97
+ if not template_path.exists():
98
+ logger.warning(
99
+ f"Template '{self._template}' not found, using 'general'."
100
+ )
101
+ template_path = Path(__file__).parent / "templates" / "general.yaml"
102
+
103
+ with open(template_path, "r", encoding="utf-8") as f:
104
+ data = yaml.safe_load(f)
89
105
 
90
106
  self._template_keywords = data.get("identity_keywords", [])
91
107
  self._reference_text = data.get("reference_text", " ".join(self._template_keywords))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ct-toolkit
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Computational Theseus Toolkit — Identity Continuity Guardrails for Agentic Systems
5
5
  Author: Hakan Damar
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ct-toolkit"
7
- version = "0.2.8"
7
+ version = "0.2.9"
8
8
  description = "Computational Theseus Toolkit — Identity Continuity Guardrails for Agentic Systems"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
File without changes
File without changes
File without changes