ct-toolkit 0.2.8__tar.gz → 0.3.0__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.
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/PKG-INFO +1 -1
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/core/kernel.py +4 -1
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/core/wrapper.py +2 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/divergence/engine.py +4 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/divergence/l2_judge.py +20 -9
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/divergence/l3_icm.py +18 -7
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/identity/embedding.py +38 -22
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit.egg-info/PKG-INFO +1 -1
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/pyproject.toml +1 -1
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/LICENSE +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/README.md +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/core/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/core/compatibility.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/core/exceptions.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/core/integrity.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/divergence/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/divergence/analysis.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/divergence/loss.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/divergence/scheduler.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/endorsement/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/endorsement/probes/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/endorsement/reflective.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/identity/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/identity/templates/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/identity/templates/defense.yaml +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/identity/templates/finance.yaml +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/identity/templates/general.yaml +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/identity/templates/medical.yaml +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/kernels/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/kernels/default.yaml +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/kernels/defense.yaml +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/middleware/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/middleware/autogen.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/middleware/crewai.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/middleware/deepagents.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/middleware/langchain.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/provenance/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/provenance/log.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/provenance/vault/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/utils/__init__.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit/utils/logger.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit.egg-info/SOURCES.txt +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit.egg-info/dependency_links.txt +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit.egg-info/requires.txt +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/ct_toolkit.egg-info/top_level.txt +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/setup.cfg +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/tests/test_analysis.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/tests/test_deep_agents_integration.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/tests/test_loss.py +0 -0
- {ct_toolkit-0.2.8 → ct_toolkit-0.3.0}/tests/test_summarization_drift.py +0 -0
|
@@ -73,12 +73,15 @@ class ConstitutionalKernel:
|
|
|
73
73
|
else:
|
|
74
74
|
with open(path, "r", encoding="utf-8") as f:
|
|
75
75
|
data = yaml.safe_load(f)
|
|
76
|
+
|
|
77
|
+
if not isinstance(data, dict):
|
|
78
|
+
data = {}
|
|
76
79
|
|
|
77
80
|
anchors = [AxiomaticAnchor(**a) for a in data.get("axiomatic_anchors", [])]
|
|
78
81
|
commitments = [PlasticCommitment(**c) for c in data.get("plastic_commitments", [])]
|
|
79
82
|
|
|
80
83
|
profile = KernelProfile(
|
|
81
|
-
name=data
|
|
84
|
+
name=data.get("name", "custom_kernel"),
|
|
82
85
|
version=data.get("version", "1.0.0"),
|
|
83
86
|
description=data.get("description", ""),
|
|
84
87
|
axiomatic_anchors=anchors,
|
|
@@ -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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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))
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ct-toolkit"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|