switch-trust-cli 1.7.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 (157) hide show
  1. switch_trust/__init__.py +0 -0
  2. switch_trust/cli/__init__.py +0 -0
  3. switch_trust/cli/__main__.py +3 -0
  4. switch_trust/cli/builtin_config.json +879 -0
  5. switch_trust/cli/console.py +127 -0
  6. switch_trust/cli/eval_cli.py +905 -0
  7. switch_trust/cli/file_filter.py +172 -0
  8. switch_trust/cli/init_cli.py +156 -0
  9. switch_trust/cli/main.py +384 -0
  10. switch_trust/cli/output_formatters.py +482 -0
  11. switch_trust/cli/rich_observer.py +89 -0
  12. switch_trust/cli/runner.py +274 -0
  13. switch_trust/cli/scan_cli.py +314 -0
  14. switch_trust/cli/telemetry.py +430 -0
  15. switch_trust/cli/utils.py +158 -0
  16. switch_trust/cli/version.py +1 -0
  17. switch_trust/data/detector_prompts/llm01_adversarial.txt +59 -0
  18. switch_trust/data/detector_prompts/llm01_fixed.txt +6 -0
  19. switch_trust/data/detector_prompts/llm02_adversarial.txt +79 -0
  20. switch_trust/data/detector_prompts/llm02_fixed.txt +6 -0
  21. switch_trust/data/detector_prompts/llm05_adversarial.txt +67 -0
  22. switch_trust/data/detector_prompts/llm05_fixed.txt +14 -0
  23. switch_trust/data/detector_prompts/llm06_adversarial.txt +139 -0
  24. switch_trust/data/detector_prompts/llm06_fixed.txt +13 -0
  25. switch_trust/data/detector_prompts/llm07_adversarial.txt +189 -0
  26. switch_trust/data/detector_prompts/llm07_fixed.txt +12 -0
  27. switch_trust/data/detector_prompts/llm09_adversarial.txt +83 -0
  28. switch_trust/data/detector_prompts/llm09_fixed.txt +13 -0
  29. switch_trust/data/llm01_prompt_injection.csv +6708 -0
  30. switch_trust/data/llm02_sensitive_information.csv +1069 -0
  31. switch_trust/data/llm05_unsafe_output.csv +3882 -0
  32. switch_trust/data/llm06_excessive_agency.csv +778 -0
  33. switch_trust/data/llm07_system_prompt_leakage.csv +971 -0
  34. switch_trust/data/llm09_hallucination-goals.csv +32419 -0
  35. switch_trust/data/llm09_hallucination.csv +599 -0
  36. switch_trust/data/pii_leakage.csv +706 -0
  37. switch_trust/data/secret_leakage.csv +1380 -0
  38. switch_trust/eval/__init__.py +0 -0
  39. switch_trust/eval/common/__init__.py +0 -0
  40. switch_trust/eval/common/converter_anthropic.py +172 -0
  41. switch_trust/eval/common/converter_genai.py +171 -0
  42. switch_trust/eval/common/converter_openai.py +198 -0
  43. switch_trust/eval/common/log.py +116 -0
  44. switch_trust/eval/common/reference.py +25 -0
  45. switch_trust/eval/common/schema.py +190 -0
  46. switch_trust/eval/common/utils.py +119 -0
  47. switch_trust/eval/core/__init__.py +0 -0
  48. switch_trust/eval/core/detectors/__init__.py +0 -0
  49. switch_trust/eval/core/detectors/detector.py +25 -0
  50. switch_trust/eval/core/detectors/detector_garak.py +112 -0
  51. switch_trust/eval/core/detectors/detector_model.py +123 -0
  52. switch_trust/eval/core/detectors/detector_model_adversarial.py +91 -0
  53. switch_trust/eval/core/detectors/detector_pii.py +67 -0
  54. switch_trust/eval/core/detectors/detector_secret.py +88 -0
  55. switch_trust/eval/core/detectors/detector_topic_guard.py +63 -0
  56. switch_trust/eval/core/detectors/detector_toxicity.py +78 -0
  57. switch_trust/eval/core/eval/__init__.py +0 -0
  58. switch_trust/eval/core/eval/eval_creator.py +166 -0
  59. switch_trust/eval/core/eval/evaluation.py +112 -0
  60. switch_trust/eval/core/eval/evaluation_adversarial.py +412 -0
  61. switch_trust/eval/core/eval/evaluation_garak_module.py +45 -0
  62. switch_trust/eval/core/eval/evaluation_garak_probe.py +308 -0
  63. switch_trust/eval/core/eval/evaluation_message_list.py +46 -0
  64. switch_trust/eval/core/eval/evaluation_multi.py +276 -0
  65. switch_trust/eval/core/eval/evaluation_single.py +89 -0
  66. switch_trust/eval/core/eval/evaluation_single_prompt.py +62 -0
  67. switch_trust/eval/core/eval/evaluation_topic_guard.py +305 -0
  68. switch_trust/eval/core/eval/metric_conciseness.py +179 -0
  69. switch_trust/eval/core/eval/metric_factual_accuracy.py +312 -0
  70. switch_trust/eval/core/eval/metric_instruction_adherence.py +177 -0
  71. switch_trust/eval/core/eval/metric_tone.py +180 -0
  72. switch_trust/eval/core/eval/metric_toxicity.py +146 -0
  73. switch_trust/eval/core/eval/observer.py +137 -0
  74. switch_trust/eval/core/message/__init__.py +0 -0
  75. switch_trust/eval/core/message/message_collection.py +37 -0
  76. switch_trust/eval/core/message/message_collection_csv.py +44 -0
  77. switch_trust/eval/core/message/message_collection_garak.py +46 -0
  78. switch_trust/eval/core/message/message_collection_memory.py +34 -0
  79. switch_trust/eval/core/models/__init__.py +0 -0
  80. switch_trust/eval/core/models/generator_model.py +421 -0
  81. switch_trust/eval/core/models/model.py +172 -0
  82. switch_trust/eval/core/models/model_adk.py +186 -0
  83. switch_trust/eval/core/models/model_anthropic.py +79 -0
  84. switch_trust/eval/core/models/model_anthropic_agent.py +104 -0
  85. switch_trust/eval/core/models/model_gemini.py +146 -0
  86. switch_trust/eval/core/models/model_generic_http.py +120 -0
  87. switch_trust/eval/core/models/model_http.py +135 -0
  88. switch_trust/eval/core/models/model_huggingface.py +75 -0
  89. switch_trust/eval/core/models/model_langserve.py +96 -0
  90. switch_trust/eval/core/models/model_litellm.py +52 -0
  91. switch_trust/eval/core/models/model_ollama.py +65 -0
  92. switch_trust/eval/core/models/model_openai.py +71 -0
  93. switch_trust/eval/core/models/model_openai_agent.py +92 -0
  94. switch_trust/eval/core/models/model_openai_compatible.py +66 -0
  95. switch_trust/eval/core/models/model_per_endpoint_limiter.py +80 -0
  96. switch_trust/eval/core/models/model_retry.py +204 -0
  97. switch_trust/eval/core/models/model_sync_wrapper.py +38 -0
  98. switch_trust/eval/core/models/model_vertex_agent_runtime.py +315 -0
  99. switch_trust/eval/core/models/response_schema.py +148 -0
  100. switch_trust/eval/core/optional_deps.py +57 -0
  101. switch_trust/eval/db/__init__.py +0 -0
  102. switch_trust/eval/db/base/__init__.py +0 -0
  103. switch_trust/eval/db/base/common_types.py +16 -0
  104. switch_trust/eval/db/base/detectors/__init__.py +0 -0
  105. switch_trust/eval/db/base/detectors/detector_helpers.py +88 -0
  106. switch_trust/eval/db/base/detectors/detector_repository.py +96 -0
  107. switch_trust/eval/db/base/detectors/detector_types.py +77 -0
  108. switch_trust/eval/db/base/eval/__init__.py +0 -0
  109. switch_trust/eval/db/base/eval/eval_helpers.py +186 -0
  110. switch_trust/eval/db/base/eval/eval_repository.py +120 -0
  111. switch_trust/eval/db/base/eval/eval_run.py +142 -0
  112. switch_trust/eval/db/base/eval/eval_types.py +127 -0
  113. switch_trust/eval/db/base/eval/model_eval_repository.py +79 -0
  114. switch_trust/eval/db/base/eval/model_eval_run_repository.py +72 -0
  115. switch_trust/eval/db/base/eval/model_eval_run_result_repository.py +42 -0
  116. switch_trust/eval/db/base/eval/model_eval_run_result_types.py +21 -0
  117. switch_trust/eval/db/base/eval/model_eval_run_types.py +78 -0
  118. switch_trust/eval/db/base/eval/model_eval_types.py +69 -0
  119. switch_trust/eval/db/base/message/__init__.py +0 -0
  120. switch_trust/eval/db/base/message/message_collection_helpers.py +50 -0
  121. switch_trust/eval/db/base/message/message_collection_repository.py +95 -0
  122. switch_trust/eval/db/base/message/message_collection_types.py +87 -0
  123. switch_trust/eval/db/base/models/__init__.py +0 -0
  124. switch_trust/eval/db/base/models/model_helpers.py +253 -0
  125. switch_trust/eval/db/base/models/model_repository.py +104 -0
  126. switch_trust/eval/db/base/models/model_types.py +159 -0
  127. switch_trust/eval/db/json/__init__.py +0 -0
  128. switch_trust/eval/db/json/repository_json.py +559 -0
  129. switch_trust/scan/__init__.py +12 -0
  130. switch_trust/scan/agent_scanner.py +812 -0
  131. switch_trust/scan/config/agent_opengrep_rules.yaml +533 -0
  132. switch_trust/scan/config/agent_taxonomy.json +517 -0
  133. switch_trust/scan/config/agentic_cvss_mapping.yaml +136 -0
  134. switch_trust/scan/config/compliance_mappings.json +110 -0
  135. switch_trust/scan/config/triage_prompt.txt +326 -0
  136. switch_trust/scan/constants.py +15 -0
  137. switch_trust/scan/exception_classification.py +179 -0
  138. switch_trust/scan/llm_provider.py +330 -0
  139. switch_trust/scan/opengrep_resolver.py +12 -0
  140. switch_trust/scan/reasoner.py +602 -0
  141. switch_trust/scan/schema.py +315 -0
  142. switch_trust/scan/scorer.py +372 -0
  143. switch_trust/scan/static_scanner.py +681 -0
  144. switch_trust/scan/taxonomy.py +121 -0
  145. switch_trust/scan/tool_dispatcher.py +773 -0
  146. switch_trust/scan/trace_logger.py +118 -0
  147. switch_trust/scan/trace_logger_file.py +143 -0
  148. switch_trust/scan/trace_logger_log.py +100 -0
  149. switch_trust/scan/triage.py +614 -0
  150. switch_trust/schema.py +79 -0
  151. switch_trust/secret_anonymizer.py +72 -0
  152. switch_trust_cli-1.7.0.dist-info/METADATA +495 -0
  153. switch_trust_cli-1.7.0.dist-info/RECORD +157 -0
  154. switch_trust_cli-1.7.0.dist-info/WHEEL +5 -0
  155. switch_trust_cli-1.7.0.dist-info/entry_points.txt +2 -0
  156. switch_trust_cli-1.7.0.dist-info/licenses/LICENSE +210 -0
  157. switch_trust_cli-1.7.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,120 @@
1
+ """
2
+ Abstract interface for a repository of Evaluations.
3
+
4
+ An EvaluationRepository manages evaluation configurations,
5
+ providing CRUD operations over them. Evaluations are
6
+ always referenced by ID.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from abc import ABC, abstractmethod
12
+
13
+ from switch_trust.eval.core.eval.evaluation import Evaluation
14
+ from switch_trust.eval.db.base.detectors.detector_repository import DetectorRepository
15
+ from switch_trust.eval.db.base.eval.eval_types import (
16
+ DbEvaluation,
17
+ EvaluationListView,
18
+ EvaluationSortOrder,
19
+ )
20
+ from switch_trust.eval.db.base.message.message_collection_repository import (
21
+ MessageCollectionRepository,
22
+ )
23
+
24
+
25
+ class EvaluationRepository(ABC):
26
+ """Repository that manages Evaluation configurations."""
27
+
28
+ @abstractmethod
29
+ def list(self) -> list[DbEvaluation]:
30
+ """Return all evaluation configurations in the repository."""
31
+ pass
32
+
33
+ @abstractmethod
34
+ def search(
35
+ self,
36
+ query: str | None = None,
37
+ types: list[str] | None = None,
38
+ order: EvaluationSortOrder | None = None,
39
+ offset: int = 0,
40
+ limit: int = 50,
41
+ ) -> EvaluationListView:
42
+ """Search evaluations by name with offset-based pagination.
43
+
44
+ Args:
45
+ query: Text to match against the evaluation name
46
+ (case-insensitive substring match).
47
+ order: Sort field and direction.
48
+ offset: Number of items to skip.
49
+ limit: Maximum number of items to return.
50
+ """
51
+ pass
52
+
53
+ @abstractmethod
54
+ def get(self, id: str) -> DbEvaluation:
55
+ """Return the evaluation configuration with the given id.
56
+
57
+ Raises KeyError if the evaluation does not exist.
58
+ """
59
+ pass
60
+
61
+ @abstractmethod
62
+ def create(
63
+ self,
64
+ config: DbEvaluation,
65
+ ) -> DbEvaluation:
66
+ """Persist a new evaluation configuration.
67
+
68
+ Raises ValueError if an evaluation with that name already
69
+ exists.
70
+ """
71
+ pass
72
+
73
+ @abstractmethod
74
+ def update(
75
+ self,
76
+ config: DbEvaluation,
77
+ ) -> DbEvaluation:
78
+ """Replace an existing evaluation configuration.
79
+
80
+ The evaluation is identified by ``config.id``.
81
+
82
+ Raises KeyError if the evaluation does not exist.
83
+ """
84
+ pass
85
+
86
+ def get_evaluation(
87
+ self,
88
+ id: str,
89
+ message_collection_repo: MessageCollectionRepository | None = None,
90
+ detector_repo: DetectorRepository | None = None,
91
+ ) -> Evaluation:
92
+ """Return an Evaluation instance for the given id.
93
+
94
+ Depending on the evaluation type, additional repositories
95
+ may be required to resolve referenced objects.
96
+
97
+ Raises KeyError if the evaluation does not exist.
98
+ """
99
+ from switch_trust.eval.db.base.eval.eval_helpers import ( # noqa: PLC0415 - deferred import cost
100
+ create_evaluation,
101
+ )
102
+
103
+ return create_evaluation(
104
+ self.get(id),
105
+ message_collection_repo=message_collection_repo,
106
+ detector_repo=detector_repo,
107
+ )
108
+
109
+ @abstractmethod
110
+ def delete(self, id: str) -> None:
111
+ """Delete the evaluation with the given id.
112
+
113
+ Raises KeyError if the evaluation does not exist.
114
+ """
115
+ pass
116
+
117
+ @abstractmethod
118
+ def clear(self) -> None:
119
+ """Remove all evaluations from the repository."""
120
+ pass
@@ -0,0 +1,142 @@
1
+ """
2
+ Standalone function to run a model evaluation end-to-end.
3
+
4
+ Looks up the DbModelEvaluation, creates the core Evaluation and
5
+ Model, creates a DbModelEvaluationRun, and executes the evaluation
6
+ with an observer that persists progress back to the database.
7
+ """
8
+
9
+ import logging
10
+
11
+ from switch_trust.eval.common.utils import now_utc
12
+ from switch_trust.eval.core.eval.evaluation import Evaluation, EvaluationStatus
13
+ from switch_trust.eval.db.base.detectors.detector_repository import DetectorRepository
14
+ from switch_trust.eval.db.base.eval.eval_repository import EvaluationRepository
15
+ from switch_trust.eval.db.base.eval.model_eval_repository import (
16
+ ModelEvaluationRepository,
17
+ )
18
+ from switch_trust.eval.db.base.eval.model_eval_run_repository import (
19
+ ModelEvaluationRunRepository,
20
+ )
21
+ from switch_trust.eval.db.base.eval.model_eval_run_result_repository import (
22
+ ModelEvaluationRunResultRepository,
23
+ )
24
+ from switch_trust.eval.db.base.eval.model_eval_run_result_types import (
25
+ DbModelEvaluationRunResult,
26
+ )
27
+ from switch_trust.eval.db.base.eval.model_eval_run_types import DbModelEvaluationRun
28
+ from switch_trust.eval.db.base.message.message_collection_repository import (
29
+ MessageCollectionRepository,
30
+ )
31
+ from switch_trust.eval.db.base.models.model_repository import ModelRepository
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ async def run_model_evaluation(
37
+ model_evaluation_id: str,
38
+ concurrency: int,
39
+ model_evaluation_repo: ModelEvaluationRepository,
40
+ evaluation_repo: EvaluationRepository,
41
+ model_repo: ModelRepository,
42
+ run_repo: ModelEvaluationRunRepository,
43
+ message_collection_repo: MessageCollectionRepository | None = None,
44
+ detector_repo: DetectorRepository | None = None,
45
+ result_repo: ModelEvaluationRunResultRepository | None = None,
46
+ run: DbModelEvaluationRun | None = None,
47
+ ) -> DbModelEvaluationRun:
48
+ """Run a model evaluation and persist progress to the database.
49
+
50
+ 1. Looks up the DbModelEvaluation by ID
51
+ 2. Creates the core Evaluation and Model from their configs
52
+ 3. Creates a new DbModelEvaluationRun and persists it
53
+ 4. Initialises and runs the evaluation with an observer
54
+ that writes the summary back after each progress update
55
+ 5. Returns the completed run
56
+
57
+ Args:
58
+ model_evaluation_id: ID of the DbModelEvaluation to run.
59
+ concurrency: Max concurrent evaluation tasks.
60
+ model_evaluation_repo: Repository for DbModelEvaluation.
61
+ evaluation_repo: Repository for DbEvaluation.
62
+ model_repo: Repository for DbModel.
63
+ run_repo: Repository for DbModelEvaluationRun.
64
+ message_collection_repo: Required for MESSAGE_COLLECTION
65
+ evaluation types.
66
+ detector_repo: Required for evaluations that use detectors.
67
+ """
68
+ model_evaluation = model_evaluation_repo.get(
69
+ model_evaluation_id,
70
+ )
71
+
72
+ evaluation = evaluation_repo.get_evaluation(
73
+ model_evaluation.evaluation_id,
74
+ message_collection_repo=message_collection_repo,
75
+ detector_repo=detector_repo,
76
+ )
77
+ model = model_repo.get_model(model_evaluation.model_id)
78
+
79
+ if run is None:
80
+ run = DbModelEvaluationRun(
81
+ model_evaluation_id=model_evaluation_id,
82
+ started=now_utc(),
83
+ )
84
+ run_repo.create(run)
85
+
86
+ logger.info(
87
+ "Run %s started for model evaluation %s",
88
+ run.id,
89
+ model_evaluation_id,
90
+ )
91
+
92
+ def _on_progress(e: Evaluation) -> None:
93
+ summary = e.get_summary()
94
+ run.summary = summary
95
+ if summary.status in (
96
+ EvaluationStatus.FINISHED,
97
+ EvaluationStatus.ERROR,
98
+ ):
99
+ run.finished = now_utc()
100
+ run_repo.update(run)
101
+ logger.info(
102
+ "Run %s: %s (%.0f%%)",
103
+ run.id,
104
+ summary.status.value,
105
+ summary.progress * 100,
106
+ )
107
+
108
+ evaluation.add_observer(_on_progress)
109
+ try:
110
+ await evaluation.init()
111
+ await evaluation.run(model, concurrency)
112
+ except Exception as e:
113
+ logger.error("Run %s failed: %s", run.id, e)
114
+ finally:
115
+ evaluation.remove_observer(_on_progress)
116
+
117
+ run.summary = evaluation.get_summary()
118
+ run.finished = now_utc()
119
+ run_repo.update(run)
120
+
121
+ if result_repo is not None:
122
+ core_results = evaluation.get_results()
123
+ db_results = [
124
+ DbModelEvaluationRunResult(
125
+ run_id=run.id,
126
+ score=r.score,
127
+ status=r.status,
128
+ error_message=r.error_message,
129
+ session=r.session,
130
+ )
131
+ for r in core_results
132
+ ]
133
+ result_repo.create_batch(db_results)
134
+ logger.info(
135
+ "Run %s: stored %d results",
136
+ run.id,
137
+ len(db_results),
138
+ )
139
+
140
+ logger.info("Run %s finished", run.id)
141
+
142
+ return run
@@ -0,0 +1,127 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+ from enum import Enum
6
+
7
+ from dataclasses_json import dataclass_json
8
+
9
+ from switch_trust.eval.common.reference import Reference, ReferenceType
10
+ from switch_trust.eval.common.utils import datetime_config, generate_id, now_utc
11
+ from switch_trust.eval.db.base.common_types import SortDirection
12
+ from switch_trust.eval.db.base.eval.model_eval_run_types import DbModelEvaluationRun
13
+
14
+
15
+ class EvaluationType(str, Enum):
16
+ """Discriminator for the kind of Evaluation."""
17
+
18
+ MESSAGE_COLLECTION = "message_collection"
19
+ GARAK_PROBE = "garak_probe"
20
+ GARAK_MODULE = "garak_module"
21
+ METRIC_TOXICITY = "metric_toxicity"
22
+ METRIC_CONCISENESS = "metric_conciseness"
23
+ METRIC_FACTUAL_ACCURACY = "metric_factual_accuracy"
24
+ METRIC_INSTRUCTION_ADHERENCE = "metric_instruction_adherence"
25
+ METRIC_TONE = "metric_tone"
26
+ ADVERSARIAL_PROBE = "adversarial_probe"
27
+ TOPIC_GUARD = "topic_guard"
28
+
29
+
30
+ class EvaluationApproach(str, Enum):
31
+ """Whether an evaluation actively probes the model
32
+ or passively measures a quality metric."""
33
+
34
+ PROBE = "Probe"
35
+ METRIC = "Metric"
36
+
37
+
38
+ @dataclass_json
39
+ @dataclass
40
+ class DbEvaluation:
41
+ """JSON-serialisable description of an Evaluation."""
42
+
43
+ type: EvaluationType
44
+ name: str
45
+ id: str = field(default_factory=generate_id)
46
+ created: datetime = field(
47
+ default_factory=now_utc,
48
+ metadata=datetime_config,
49
+ )
50
+ description: str | None = None
51
+ approach: EvaluationApproach = EvaluationApproach.PROBE
52
+ tags: dict[str, str] = field(default_factory=dict)
53
+
54
+ # -- shared (message_collection, adversarial_probe) --
55
+ message_collection_id: str | None = None
56
+ detector_id: str | None = None
57
+
58
+ # -- garak_probe type --
59
+ probe_name: str | None = None
60
+
61
+ # -- garak_module type --
62
+ module_name: str | None = None
63
+ probe_names: list[str] | None = None
64
+
65
+ # -- adversarial_probe type --
66
+ adversarial_goals: list[str] | None = None
67
+ attack_techniques: list[str] | None = None
68
+ num_prompts: int | None = None
69
+ max_turns: int | None = None
70
+
71
+ # -- topic_guard type --
72
+ agent_objective: str | None = None
73
+ agent_instructions: str | None = None
74
+
75
+ def get_ref(self) -> Reference:
76
+ return Reference(
77
+ self.id,
78
+ self.name,
79
+ ReferenceType.EVALUATION,
80
+ self.description,
81
+ )
82
+
83
+
84
+ class EvaluationSortField(str, Enum):
85
+ NAME = "name"
86
+ CREATED = "created"
87
+ TYPE = "type"
88
+
89
+
90
+ @dataclass_json
91
+ @dataclass
92
+ class EvaluationSortOrder:
93
+ field: EvaluationSortField = EvaluationSortField.NAME
94
+ direction: SortDirection = SortDirection.ASC
95
+
96
+
97
+ @dataclass_json
98
+ @dataclass
99
+ class EvaluationListView:
100
+ """Paginated list of evaluation configurations."""
101
+
102
+ items: list[DbEvaluation] = field(default_factory=list)
103
+ total: int = 0
104
+
105
+
106
+ @dataclass_json
107
+ @dataclass
108
+ class EvaluationDetailModelView:
109
+ """A model assigned to an evaluation, with last run info."""
110
+
111
+ id: str
112
+ model_ref: Reference
113
+ evaluation_ref: Reference
114
+ created: datetime = field(metadata=datetime_config)
115
+ weight: float = 0.5
116
+ last_run: DbModelEvaluationRun | None = None
117
+
118
+
119
+ @dataclass_json
120
+ @dataclass
121
+ class EvaluationDetailView:
122
+ """An evaluation with its assigned models."""
123
+
124
+ config: DbEvaluation | None = None
125
+ models: list[EvaluationDetailModelView] = field(
126
+ default_factory=list,
127
+ )
@@ -0,0 +1,79 @@
1
+ """
2
+ Abstract interface for a repository of ModelEvaluations.
3
+
4
+ A ModelEvaluationRepository manages the assignments of
5
+ Evaluations to Models.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+
10
+ from switch_trust.eval.db.base.eval.model_eval_types import (
11
+ DbModelEvaluation,
12
+ ModelEvaluationListView,
13
+ ModelEvaluationSortOrder,
14
+ )
15
+
16
+
17
+ class ModelEvaluationRepository(ABC):
18
+ """Repository that manages ModelEvaluation assignments."""
19
+
20
+ @abstractmethod
21
+ def list_by_model(
22
+ self,
23
+ model_id: str,
24
+ order: ModelEvaluationSortOrder | None = None,
25
+ offset: int = 0,
26
+ limit: int = 50,
27
+ ) -> ModelEvaluationListView:
28
+ """Return assignments for a given model with pagination.
29
+
30
+ Args:
31
+ model_id: The model to list assignments for.
32
+ order: Sort field and direction.
33
+ offset: Number of items to skip.
34
+ limit: Maximum number of items to return.
35
+ """
36
+ pass
37
+
38
+ @abstractmethod
39
+ def get(self, id: str) -> DbModelEvaluation:
40
+ """Return the assignment with the given id.
41
+
42
+ Raises KeyError if it does not exist.
43
+ """
44
+ pass
45
+
46
+ @abstractmethod
47
+ def create(
48
+ self,
49
+ config: DbModelEvaluation,
50
+ ) -> DbModelEvaluation:
51
+ """Persist a new model-evaluation assignment.
52
+
53
+ Raises ValueError if an assignment with that name
54
+ already exists.
55
+ """
56
+ pass
57
+
58
+ @abstractmethod
59
+ def list_by_evaluation(
60
+ self,
61
+ evaluation_id: str,
62
+ order: ModelEvaluationSortOrder | None = None,
63
+ offset: int = 0,
64
+ limit: int = 50,
65
+ ) -> ModelEvaluationListView:
66
+ """Return assignments for a given evaluation with pagination.
67
+
68
+ Args:
69
+ evaluation_id: The evaluation to list assignments for.
70
+ order: Sort field and direction.
71
+ offset: Number of items to skip.
72
+ limit: Maximum number of items to return.
73
+ """
74
+ pass
75
+
76
+ @abstractmethod
77
+ def clear(self) -> None:
78
+ """Remove all model-evaluation assignments."""
79
+ pass
@@ -0,0 +1,72 @@
1
+ """
2
+ Abstract interface for a repository of ModelEvaluationRuns.
3
+
4
+ A ModelEvaluationRunRepository manages runs of model-evaluation
5
+ assignments, providing create and search operations.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+
10
+ from switch_trust.eval.db.base.eval.model_eval_run_types import (
11
+ DbModelEvaluationRun,
12
+ ModelEvaluationRunListView,
13
+ ModelEvaluationRunSortOrder,
14
+ )
15
+
16
+
17
+ class ModelEvaluationRunRepository(ABC):
18
+ """Repository that manages ModelEvaluationRun records."""
19
+
20
+ @abstractmethod
21
+ def create(
22
+ self,
23
+ run: DbModelEvaluationRun,
24
+ ) -> DbModelEvaluationRun:
25
+ """Persist a new run."""
26
+ pass
27
+
28
+ @abstractmethod
29
+ def get(self, id: str) -> DbModelEvaluationRun:
30
+ """Return the run with the given id.
31
+
32
+ Raises KeyError if it does not exist.
33
+ """
34
+ pass
35
+
36
+ @abstractmethod
37
+ def update(
38
+ self,
39
+ run: DbModelEvaluationRun,
40
+ ) -> DbModelEvaluationRun:
41
+ """Update the summary and finished timestamp of a run.
42
+
43
+ The run is identified by ``run.id``.
44
+
45
+ Raises KeyError if the run does not exist.
46
+ """
47
+ pass
48
+
49
+ @abstractmethod
50
+ def search(
51
+ self,
52
+ model_evaluation_id: str | None = None,
53
+ model_id: str | None = None,
54
+ evaluation_id: str | None = None,
55
+ order: ModelEvaluationRunSortOrder | None = None,
56
+ offset: int = 0,
57
+ limit: int = 50,
58
+ ) -> ModelEvaluationRunListView:
59
+ """Search runs with optional filter and pagination.
60
+
61
+ Args:
62
+ model_evaluation_id: Filter by model-evaluation ID.
63
+ order: Sort field and direction.
64
+ offset: Number of items to skip.
65
+ limit: Maximum number of items to return.
66
+ """
67
+ pass
68
+
69
+ @abstractmethod
70
+ def clear(self) -> None:
71
+ """Remove all runs."""
72
+ pass
@@ -0,0 +1,42 @@
1
+ """
2
+ Abstract interface for a repository of ModelEvaluationRunResults.
3
+
4
+ A ModelEvaluationRunResultRepository manages the leaf-evaluation
5
+ results that belong to a model-evaluation run.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+
10
+ from switch_trust.eval.db.base.eval.model_eval_run_result_types import (
11
+ DbModelEvaluationRunResult,
12
+ )
13
+
14
+
15
+ class ModelEvaluationRunResultRepository(ABC):
16
+ """Repository that manages ModelEvaluationRunResult records."""
17
+
18
+ @abstractmethod
19
+ def create_batch(
20
+ self,
21
+ results: list[DbModelEvaluationRunResult],
22
+ ) -> None:
23
+ """Persist a batch of results for a run."""
24
+ pass
25
+
26
+ @abstractmethod
27
+ def get_by_run_id(
28
+ self,
29
+ run_id: str,
30
+ ) -> list[DbModelEvaluationRunResult]:
31
+ """Return all results for a given run."""
32
+ pass
33
+
34
+ @abstractmethod
35
+ def delete_by_run_id(self, run_id: str) -> None:
36
+ """Remove all results for a given run."""
37
+ pass
38
+
39
+ @abstractmethod
40
+ def clear(self) -> None:
41
+ """Remove all results."""
42
+ pass
@@ -0,0 +1,21 @@
1
+ from dataclasses import dataclass, field
2
+
3
+ from dataclasses_json import dataclass_json
4
+
5
+ from switch_trust.eval.common.schema import Session
6
+ from switch_trust.eval.common.utils import generate_id
7
+ from switch_trust.eval.core.eval.evaluation import EvaluationStatus
8
+
9
+
10
+ @dataclass_json
11
+ @dataclass
12
+ class DbModelEvaluationRunResult:
13
+ """A single leaf-evaluation result within a run."""
14
+
15
+ run_id: str
16
+ score: float
17
+ status: EvaluationStatus
18
+ id: str = field(default_factory=generate_id)
19
+ error_message: str | None = None
20
+ tags: dict[str, str] = field(default_factory=dict)
21
+ session: Session | None = None
@@ -0,0 +1,78 @@
1
+ from dataclasses import dataclass, field
2
+ from datetime import datetime
3
+ from enum import Enum
4
+
5
+ from dataclasses_json import dataclass_json
6
+
7
+ from switch_trust.eval.common.reference import Reference
8
+ from switch_trust.eval.common.utils import datetime_config, generate_id, now_utc
9
+ from switch_trust.eval.core.eval.evaluation import EvaluationSummary
10
+ from switch_trust.eval.db.base.common_types import SortDirection
11
+
12
+
13
+ @dataclass_json
14
+ @dataclass
15
+ class DbModelEvaluationRun:
16
+ """A single run of a DbModelEvaluation."""
17
+
18
+ model_evaluation_id: str
19
+ id: str = field(default_factory=generate_id)
20
+ created: datetime = field(
21
+ default_factory=now_utc,
22
+ metadata=datetime_config,
23
+ )
24
+ started: datetime | None = field(
25
+ default=None,
26
+ metadata=datetime_config,
27
+ )
28
+ finished: datetime | None = field(
29
+ default=None,
30
+ metadata=datetime_config,
31
+ )
32
+ tags: dict[str, str] = field(default_factory=dict)
33
+ summary: EvaluationSummary | None = None
34
+
35
+
36
+ class ModelEvaluationRunSortField(str, Enum):
37
+ CREATED = "created"
38
+ STARTED = "started_at"
39
+ FINISHED = "finished_at"
40
+ SCORE = "score"
41
+
42
+
43
+ @dataclass_json
44
+ @dataclass
45
+ class ModelEvaluationRunSortOrder:
46
+ field: ModelEvaluationRunSortField = ModelEvaluationRunSortField.CREATED
47
+ direction: SortDirection = SortDirection.DESC
48
+
49
+
50
+ @dataclass_json
51
+ @dataclass
52
+ class ModelEvaluationRunDetailView:
53
+ """A model-evaluation run with resolved references."""
54
+
55
+ run: DbModelEvaluationRun
56
+ model_ref: Reference | None = None
57
+ evaluation_ref: Reference | None = None
58
+
59
+
60
+ @dataclass_json
61
+ @dataclass
62
+ class ModelEvaluationRunListItem:
63
+ """A model-evaluation run with resolved references."""
64
+
65
+ run: DbModelEvaluationRun
66
+ model_ref: Reference | None = None
67
+ evaluation_ref: Reference | None = None
68
+
69
+
70
+ @dataclass_json
71
+ @dataclass
72
+ class ModelEvaluationRunListView:
73
+ """Paginated list of model-evaluation runs."""
74
+
75
+ items: list[ModelEvaluationRunListItem] = field(
76
+ default_factory=list,
77
+ )
78
+ total: int = 0