minima-cli 0.4.9__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 (161) hide show
  1. minima/__init__.py +5 -0
  2. minima/api/__init__.py +1 -0
  3. minima/api/auth.py +39 -0
  4. minima/api/errors.py +40 -0
  5. minima/api/routers/__init__.py +1 -0
  6. minima/api/routers/calibration.py +50 -0
  7. minima/api/routers/feedback.py +279 -0
  8. minima/api/routers/health.py +50 -0
  9. minima/api/routers/models.py +42 -0
  10. minima/api/routers/recommend.py +66 -0
  11. minima/api/routers/savings.py +55 -0
  12. minima/api/routers/strategies.py +33 -0
  13. minima/catalog/__init__.py +1 -0
  14. minima/catalog/data/capability_priors.json +210 -0
  15. minima/catalog/data/model_aliases.json +12 -0
  16. minima/catalog/merge.py +69 -0
  17. minima/catalog/refresh.py +54 -0
  18. minima/catalog/sources/__init__.py +1 -0
  19. minima/catalog/sources/litellm.py +19 -0
  20. minima/catalog/sources/openrouter.py +25 -0
  21. minima/catalog/store.py +86 -0
  22. minima/config.py +288 -0
  23. minima/deps.py +35 -0
  24. minima/llm/__init__.py +1 -0
  25. minima/llm/anthropic.py +106 -0
  26. minima/llm/base.py +196 -0
  27. minima/llm/gemini.py +124 -0
  28. minima/llm/registry.py +54 -0
  29. minima/logging.py +28 -0
  30. minima/main.py +109 -0
  31. minima/memory/__init__.py +1 -0
  32. minima/memory/adapter.py +572 -0
  33. minima/memory/keys.py +83 -0
  34. minima/memory/records.py +190 -0
  35. minima/memory/threadpool.py +41 -0
  36. minima/metrics/__init__.py +1 -0
  37. minima/metrics/calibration.py +415 -0
  38. minima/metrics/report.py +116 -0
  39. minima/metrics/savings.py +98 -0
  40. minima/recommender/__init__.py +1 -0
  41. minima/recommender/_pg_pool.py +38 -0
  42. minima/recommender/_redis_client.py +32 -0
  43. minima/recommender/aggregate.py +157 -0
  44. minima/recommender/classify.py +165 -0
  45. minima/recommender/decisionlog.py +505 -0
  46. minima/recommender/durablerefs.py +312 -0
  47. minima/recommender/engine.py +997 -0
  48. minima/recommender/escalation.py +83 -0
  49. minima/recommender/propensity.py +189 -0
  50. minima/recommender/recstore.py +368 -0
  51. minima/recommender/score.py +318 -0
  52. minima/recommender/types.py +166 -0
  53. minima/schemas/__init__.py +1 -0
  54. minima/schemas/common.py +73 -0
  55. minima/schemas/feedback.py +34 -0
  56. minima/schemas/models_catalog.py +36 -0
  57. minima/schemas/recommend.py +104 -0
  58. minima/schemas/savings.py +39 -0
  59. minima/schemas/strategies.py +57 -0
  60. minima/schemas/workflow.py +43 -0
  61. minima/seeding/__init__.py +1 -0
  62. minima/seeding/items.py +42 -0
  63. minima/seeding/llmrouterbench.py +232 -0
  64. minima/seeding/routerbench.py +141 -0
  65. minima/seeding/run_seed.py +56 -0
  66. minima/seeding/synthetic.py +70 -0
  67. minima/tenancy/__init__.py +8 -0
  68. minima/tenancy/context.py +37 -0
  69. minima/tenancy/passthrough.py +110 -0
  70. minima/version.py +3 -0
  71. minima_cli-0.4.9.dist-info/METADATA +275 -0
  72. minima_cli-0.4.9.dist-info/RECORD +161 -0
  73. minima_cli-0.4.9.dist-info/WHEEL +4 -0
  74. minima_cli-0.4.9.dist-info/entry_points.txt +5 -0
  75. minima_cli-0.4.9.dist-info/licenses/LICENSE +295 -0
  76. minima_client/__init__.py +19 -0
  77. minima_client/autocapture.py +101 -0
  78. minima_client/client.py +301 -0
  79. minima_client/errors.py +23 -0
  80. minima_harness/LICENSE_PI +32 -0
  81. minima_harness/__init__.py +16 -0
  82. minima_harness/agent/__init__.py +72 -0
  83. minima_harness/agent/agent.py +276 -0
  84. minima_harness/agent/events.py +124 -0
  85. minima_harness/agent/loop.py +311 -0
  86. minima_harness/agent/state.py +79 -0
  87. minima_harness/agent/tools.py +97 -0
  88. minima_harness/ai/__init__.py +66 -0
  89. minima_harness/ai/compat.py +71 -0
  90. minima_harness/ai/errors.py +96 -0
  91. minima_harness/ai/events.py +117 -0
  92. minima_harness/ai/openrouter_catalog.py +153 -0
  93. minima_harness/ai/provider_catalog.py +299 -0
  94. minima_harness/ai/provider_quirks.py +37 -0
  95. minima_harness/ai/providers/__init__.py +75 -0
  96. minima_harness/ai/providers/_common.py +48 -0
  97. minima_harness/ai/providers/anthropic.py +290 -0
  98. minima_harness/ai/providers/base.py +65 -0
  99. minima_harness/ai/providers/faux.py +173 -0
  100. minima_harness/ai/providers/google.py +221 -0
  101. minima_harness/ai/providers/openai_compat.py +278 -0
  102. minima_harness/ai/registry.py +184 -0
  103. minima_harness/ai/stream.py +82 -0
  104. minima_harness/ai/tools.py +51 -0
  105. minima_harness/ai/types.py +204 -0
  106. minima_harness/ai/usage.py +41 -0
  107. minima_harness/minima/__init__.py +40 -0
  108. minima_harness/minima/cache.py +102 -0
  109. minima_harness/minima/config.py +85 -0
  110. minima_harness/minima/goals.py +226 -0
  111. minima_harness/minima/judge.py +144 -0
  112. minima_harness/minima/mapping.py +147 -0
  113. minima_harness/minima/meter.py +143 -0
  114. minima_harness/minima/router.py +220 -0
  115. minima_harness/minima/runtime.py +544 -0
  116. minima_harness/minima/signals.py +195 -0
  117. minima_harness/session/__init__.py +14 -0
  118. minima_harness/session/format.py +35 -0
  119. minima_harness/session/store.py +236 -0
  120. minima_harness/tasks/__init__.py +17 -0
  121. minima_harness/tasks/task_set.py +78 -0
  122. minima_harness/tools/__init__.py +7 -0
  123. minima_harness/tools/_io.py +34 -0
  124. minima_harness/tools/bash.py +70 -0
  125. minima_harness/tools/builtin.py +23 -0
  126. minima_harness/tools/edit.py +50 -0
  127. minima_harness/tools/find.py +38 -0
  128. minima_harness/tools/grep.py +73 -0
  129. minima_harness/tools/ls.py +35 -0
  130. minima_harness/tools/read.py +38 -0
  131. minima_harness/tools/tasks.py +75 -0
  132. minima_harness/tools/write.py +36 -0
  133. minima_harness/tui/__init__.py +3 -0
  134. minima_harness/tui/analytics.py +111 -0
  135. minima_harness/tui/app.py +1927 -0
  136. minima_harness/tui/bridge.py +103 -0
  137. minima_harness/tui/cli.py +227 -0
  138. minima_harness/tui/clipboard.py +60 -0
  139. minima_harness/tui/commands.py +49 -0
  140. minima_harness/tui/compaction.py +17 -0
  141. minima_harness/tui/config_cli.py +141 -0
  142. minima_harness/tui/config_store.py +237 -0
  143. minima_harness/tui/context.py +93 -0
  144. minima_harness/tui/customize.py +95 -0
  145. minima_harness/tui/diff.py +53 -0
  146. minima_harness/tui/editor.py +43 -0
  147. minima_harness/tui/extensions.py +84 -0
  148. minima_harness/tui/extra_models.py +52 -0
  149. minima_harness/tui/history.py +71 -0
  150. minima_harness/tui/mubit.py +295 -0
  151. minima_harness/tui/overlays.py +593 -0
  152. minima_harness/tui/packages.py +59 -0
  153. minima_harness/tui/run_modes.py +66 -0
  154. minima_harness/tui/theme.py +77 -0
  155. minima_harness/tui/welcome.py +83 -0
  156. minima_harness/tui/widgets/__init__.py +3 -0
  157. minima_harness/tui/widgets/banner.py +38 -0
  158. minima_harness/tui/widgets/editor.py +83 -0
  159. minima_harness/tui/widgets/footer.py +73 -0
  160. minima_harness/tui/widgets/messages.py +151 -0
  161. minima_harness/tui/widgets/status.py +57 -0
@@ -0,0 +1,301 @@
1
+ """Sync and async clients mirroring the Minima endpoints."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from minima.schemas.common import Constraints, OutcomeLabel, TaskInput
10
+ from minima.schemas.feedback import FeedbackRequest, FeedbackResponse
11
+ from minima.schemas.models_catalog import ModelsResponse
12
+ from minima.schemas.recommend import RecommendRequest, RecommendResponse
13
+ from minima.schemas.savings import CalibrationResponse, SavingsResponse
14
+ from minima.schemas.strategies import StrategiesResponse
15
+ from minima.schemas.workflow import WorkflowRequest, WorkflowResponse
16
+ from minima_client.errors import raise_for_status
17
+
18
+
19
+ def _report_params(
20
+ namespace: str | None, days: float | None, group_by: str | None = None
21
+ ) -> dict[str, Any]:
22
+ params: dict[str, Any] = {}
23
+ if namespace is not None:
24
+ params["namespace"] = namespace
25
+ if days is not None:
26
+ params["days"] = days
27
+ if group_by is not None:
28
+ params["group_by"] = group_by
29
+ return params
30
+
31
+ TaskLike = str | TaskInput | dict[str, Any]
32
+
33
+
34
+ def _coerce_task(task: TaskLike) -> TaskInput:
35
+ if isinstance(task, TaskInput):
36
+ return task
37
+ if isinstance(task, str):
38
+ return TaskInput(task=task)
39
+ if isinstance(task, dict):
40
+ return TaskInput(**task)
41
+ raise TypeError(f"unsupported task type: {type(task)!r}")
42
+
43
+
44
+ def _headers(api_key: str | None) -> dict[str, str]:
45
+ return {"Authorization": f"Bearer {api_key}"} if api_key else {}
46
+
47
+
48
+ def _feedback_request(
49
+ recommendation_id: str,
50
+ chosen_model_id: str,
51
+ outcome: OutcomeLabel | str,
52
+ **kwargs: Any,
53
+ ) -> FeedbackRequest:
54
+ return FeedbackRequest(
55
+ recommendation_id=recommendation_id,
56
+ chosen_model_id=chosen_model_id,
57
+ outcome=OutcomeLabel(outcome),
58
+ **kwargs,
59
+ )
60
+
61
+
62
+ class MinimaClient:
63
+ def __init__(self, base_url: str, api_key: str | None = None, timeout: float = 10.0):
64
+ self._client = httpx.Client(
65
+ base_url=base_url.rstrip("/"), headers=_headers(api_key), timeout=timeout
66
+ )
67
+
68
+ def close(self) -> None:
69
+ self._client.close()
70
+
71
+ def __enter__(self) -> MinimaClient:
72
+ return self
73
+
74
+ def __exit__(self, *exc: object) -> None:
75
+ self.close()
76
+
77
+ def _post(self, path: str, model: Any) -> Any:
78
+ resp = self._client.post(path, json=model.model_dump(mode="json"))
79
+ raise_for_status(resp)
80
+ return resp.json()
81
+
82
+ def recommend(
83
+ self,
84
+ task: TaskLike,
85
+ *,
86
+ cost_quality_tradeoff: float = 5.0,
87
+ constraints: Constraints | None = None,
88
+ user_id: str | None = None,
89
+ namespace: str | None = None,
90
+ allow_llm_escalation: bool = True,
91
+ explain: bool = True,
92
+ baseline_model_id: str | None = None,
93
+ ) -> RecommendResponse:
94
+ req = RecommendRequest(
95
+ task=_coerce_task(task),
96
+ cost_quality_tradeoff=cost_quality_tradeoff,
97
+ constraints=constraints or Constraints(),
98
+ user_id=user_id,
99
+ namespace=namespace,
100
+ allow_llm_escalation=allow_llm_escalation,
101
+ explain=explain,
102
+ baseline_model_id=baseline_model_id,
103
+ )
104
+ return RecommendResponse.model_validate(self._post("/v1/recommend", req))
105
+
106
+ def recommend_workflow(self, req: WorkflowRequest) -> WorkflowResponse:
107
+ return WorkflowResponse.model_validate(self._post("/v1/recommend/workflow", req))
108
+
109
+ def savings(
110
+ self,
111
+ namespace: str | None = None,
112
+ days: float | None = None,
113
+ group_by: str | None = None,
114
+ ) -> SavingsResponse:
115
+ """Counterfactual savings + routing health for your org (estimated AND realized)."""
116
+ resp = self._client.get("/v1/savings", params=_report_params(namespace, days, group_by))
117
+ raise_for_status(resp)
118
+ return SavingsResponse.model_validate(resp.json())
119
+
120
+ def calibration(
121
+ self,
122
+ namespace: str | None = None,
123
+ days: float | None = None,
124
+ ) -> CalibrationResponse:
125
+ """Is predicted_success telling the truth? ECE, reliability, and drift flags."""
126
+ resp = self._client.get("/v1/calibration", params=_report_params(namespace, days))
127
+ raise_for_status(resp)
128
+ return CalibrationResponse.model_validate(resp.json())
129
+
130
+ def feedback(
131
+ self,
132
+ recommendation_id: str,
133
+ chosen_model_id: str,
134
+ outcome: OutcomeLabel | str,
135
+ **kwargs: Any,
136
+ ) -> FeedbackResponse:
137
+ req = _feedback_request(recommendation_id, chosen_model_id, outcome, **kwargs)
138
+ return FeedbackResponse.model_validate(self._post("/v1/feedback", req))
139
+
140
+ def models(
141
+ self,
142
+ provider: str | None = None,
143
+ task_type: str | None = None,
144
+ max_cost: float | None = None,
145
+ include_stale: bool = True,
146
+ ) -> ModelsResponse:
147
+ params = {
148
+ k: v
149
+ for k, v in {
150
+ "provider": provider,
151
+ "task_type": task_type,
152
+ "max_cost": max_cost,
153
+ "include_stale": include_stale,
154
+ }.items()
155
+ if v is not None
156
+ }
157
+ resp = self._client.get("/v1/models", params=params)
158
+ raise_for_status(resp)
159
+ return ModelsResponse.model_validate(resp.json())
160
+
161
+ def strategies(
162
+ self,
163
+ namespace: str | None = None,
164
+ max_strategies: int = 5,
165
+ lesson_types: list[str] | None = None,
166
+ ) -> StrategiesResponse:
167
+ params: dict[str, Any] = {"max_strategies": max_strategies}
168
+ if namespace is not None:
169
+ params["namespace"] = namespace
170
+ if lesson_types:
171
+ params["lesson_types"] = lesson_types
172
+ resp = self._client.get("/v1/strategies", params=params)
173
+ raise_for_status(resp)
174
+ return StrategiesResponse.model_validate(resp.json())
175
+
176
+ def health(self) -> dict[str, Any]:
177
+ resp = self._client.get("/v1/health")
178
+ raise_for_status(resp)
179
+ return resp.json()
180
+
181
+
182
+ class AsyncMinimaClient:
183
+ def __init__(self, base_url: str, api_key: str | None = None, timeout: float = 10.0):
184
+ self._client = httpx.AsyncClient(
185
+ base_url=base_url.rstrip("/"), headers=_headers(api_key), timeout=timeout
186
+ )
187
+
188
+ async def aclose(self) -> None:
189
+ await self._client.aclose()
190
+
191
+ async def __aenter__(self) -> AsyncMinimaClient:
192
+ return self
193
+
194
+ async def __aexit__(self, *exc: object) -> None:
195
+ await self.aclose()
196
+
197
+ async def _post(self, path: str, model: Any) -> Any:
198
+ resp = await self._client.post(path, json=model.model_dump(mode="json"))
199
+ raise_for_status(resp)
200
+ return resp.json()
201
+
202
+ async def recommend(
203
+ self,
204
+ task: TaskLike,
205
+ *,
206
+ cost_quality_tradeoff: float = 5.0,
207
+ constraints: Constraints | None = None,
208
+ user_id: str | None = None,
209
+ namespace: str | None = None,
210
+ allow_llm_escalation: bool = True,
211
+ explain: bool = True,
212
+ baseline_model_id: str | None = None,
213
+ ) -> RecommendResponse:
214
+ req = RecommendRequest(
215
+ task=_coerce_task(task),
216
+ cost_quality_tradeoff=cost_quality_tradeoff,
217
+ constraints=constraints or Constraints(),
218
+ user_id=user_id,
219
+ namespace=namespace,
220
+ allow_llm_escalation=allow_llm_escalation,
221
+ explain=explain,
222
+ baseline_model_id=baseline_model_id,
223
+ )
224
+ return RecommendResponse.model_validate(await self._post("/v1/recommend", req))
225
+
226
+ async def recommend_workflow(self, req: WorkflowRequest) -> WorkflowResponse:
227
+ return WorkflowResponse.model_validate(await self._post("/v1/recommend/workflow", req))
228
+
229
+ async def savings(
230
+ self,
231
+ namespace: str | None = None,
232
+ days: float | None = None,
233
+ group_by: str | None = None,
234
+ ) -> SavingsResponse:
235
+ """Counterfactual savings + routing health for your org (estimated AND realized)."""
236
+ resp = await self._client.get(
237
+ "/v1/savings", params=_report_params(namespace, days, group_by)
238
+ )
239
+ raise_for_status(resp)
240
+ return SavingsResponse.model_validate(resp.json())
241
+
242
+ async def calibration(
243
+ self,
244
+ namespace: str | None = None,
245
+ days: float | None = None,
246
+ ) -> CalibrationResponse:
247
+ """Is predicted_success telling the truth? ECE, reliability, and drift flags."""
248
+ resp = await self._client.get("/v1/calibration", params=_report_params(namespace, days))
249
+ raise_for_status(resp)
250
+ return CalibrationResponse.model_validate(resp.json())
251
+
252
+ async def feedback(
253
+ self,
254
+ recommendation_id: str,
255
+ chosen_model_id: str,
256
+ outcome: OutcomeLabel | str,
257
+ **kwargs: Any,
258
+ ) -> FeedbackResponse:
259
+ req = _feedback_request(recommendation_id, chosen_model_id, outcome, **kwargs)
260
+ return FeedbackResponse.model_validate(await self._post("/v1/feedback", req))
261
+
262
+ async def strategies(
263
+ self,
264
+ namespace: str | None = None,
265
+ max_strategies: int = 5,
266
+ lesson_types: list[str] | None = None,
267
+ ) -> StrategiesResponse:
268
+ params: dict[str, Any] = {"max_strategies": max_strategies}
269
+ if namespace is not None:
270
+ params["namespace"] = namespace
271
+ if lesson_types:
272
+ params["lesson_types"] = lesson_types
273
+ resp = await self._client.get("/v1/strategies", params=params)
274
+ raise_for_status(resp)
275
+ return StrategiesResponse.model_validate(resp.json())
276
+
277
+ async def models(
278
+ self,
279
+ provider: str | None = None,
280
+ task_type: str | None = None,
281
+ max_cost: float | None = None,
282
+ include_stale: bool = True,
283
+ ) -> ModelsResponse:
284
+ params = {
285
+ k: v
286
+ for k, v in {
287
+ "provider": provider,
288
+ "task_type": task_type,
289
+ "max_cost": max_cost,
290
+ "include_stale": include_stale,
291
+ }.items()
292
+ if v is not None
293
+ }
294
+ resp = await self._client.get("/v1/models", params=params)
295
+ raise_for_status(resp)
296
+ return ModelsResponse.model_validate(resp.json())
297
+
298
+ async def health(self) -> dict[str, Any]:
299
+ resp = await self._client.get("/v1/health")
300
+ raise_for_status(resp)
301
+ return resp.json()
@@ -0,0 +1,23 @@
1
+ """Client error type."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import httpx
6
+
7
+
8
+ class MinimaError(Exception):
9
+ def __init__(self, status: int, detail: str):
10
+ super().__init__(f"minima error {status}: {detail}")
11
+ self.status = status
12
+ self.detail = detail
13
+
14
+
15
+ def raise_for_status(resp: httpx.Response) -> None:
16
+ if resp.status_code < 400:
17
+ return
18
+ try:
19
+ body = resp.json()
20
+ detail = body.get("detail") or body.get("title") or str(body)
21
+ except Exception: # noqa: BLE001
22
+ detail = resp.text
23
+ raise MinimaError(resp.status_code, detail)
@@ -0,0 +1,32 @@
1
+ MIT License Attribution
2
+ =======================
3
+
4
+ Portions of this package (`src/minima_harness/`) are derived from the
5
+ `@earendil-works/pi <https://github.com/earendil-works/pi>`_ project, which is
6
+ licensed under the MIT License:
7
+
8
+ MIT License
9
+
10
+ Copyright (c) the @earendil-works/pi contributors
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+
30
+ This is a from-scratch Python port of design and APIs; no source code was copied
31
+ verbatim. The Minima integration layer (`src/minima_harness/minima/`) is original
32
+ work and is governed by the project's own license.
@@ -0,0 +1,16 @@
1
+ """minima_harness — a lean Python port of @earendil-works/pi's agent harness, made
2
+ Minima-native (routes each turn through Minima's recommender and feeds outcomes back).
3
+
4
+ Phase 0 ships the unified LLM API surface (``minima_harness.ai``), the task corpus
5
+ (``minima_harness.tasks``), and harness config (``minima_harness.minima.HarnessConfig``).
6
+ The ported agent runtime and the Minima router land in later phases.
7
+
8
+ Derived from the MIT-licensed @earendil-works/pi (see LICENSE_PI).
9
+ """
10
+
11
+ from minima_harness import ai, minima, tasks
12
+ from minima_harness.minima.config import HarnessConfig
13
+
14
+ __version__ = "0.1.0"
15
+
16
+ __all__ = ["HarnessConfig", "__version__", "ai", "minima", "tasks"]
@@ -0,0 +1,72 @@
1
+ """minima_harness.agent — ported pi-agent-core: Agent + agent_loop + events + tools."""
2
+
3
+ from minima_harness.agent.agent import Agent
4
+ from minima_harness.agent.events import (
5
+ AgentEndEvent,
6
+ AgentEvent,
7
+ AgentStartEvent,
8
+ MessageEndEvent,
9
+ MessageStartEvent,
10
+ MessageUpdateEvent,
11
+ ToolExecutionEndEvent,
12
+ ToolExecutionStartEvent,
13
+ ToolExecutionUpdateEvent,
14
+ TurnEndEvent,
15
+ TurnStartEvent,
16
+ )
17
+ from minima_harness.agent.loop import agent_loop, agent_loop_continue
18
+ from minima_harness.agent.state import (
19
+ AgentLoopConfig,
20
+ AgentState,
21
+ ConvertToLlm,
22
+ TransformContext,
23
+ default_convert_to_llm,
24
+ )
25
+ from minima_harness.agent.tools import (
26
+ AfterToolCall,
27
+ AfterToolCallContext,
28
+ AfterToolCallResult,
29
+ AgentTool,
30
+ BeforeToolCall,
31
+ BeforeToolCallContext,
32
+ BeforeToolCallResult,
33
+ ThinkingLevel,
34
+ ToolExecutionMode,
35
+ ToolResult,
36
+ error_result,
37
+ find_agent_tool,
38
+ )
39
+
40
+ __all__ = [
41
+ "AfterToolCall",
42
+ "AfterToolCallContext",
43
+ "AfterToolCallResult",
44
+ "Agent",
45
+ "AgentEndEvent",
46
+ "AgentEvent",
47
+ "AgentLoopConfig",
48
+ "AgentStartEvent",
49
+ "AgentState",
50
+ "AgentTool",
51
+ "BeforeToolCall",
52
+ "BeforeToolCallContext",
53
+ "BeforeToolCallResult",
54
+ "ConvertToLlm",
55
+ "MessageEndEvent",
56
+ "MessageStartEvent",
57
+ "MessageUpdateEvent",
58
+ "ThinkingLevel",
59
+ "ToolExecutionEndEvent",
60
+ "ToolExecutionMode",
61
+ "ToolExecutionStartEvent",
62
+ "ToolExecutionUpdateEvent",
63
+ "ToolResult",
64
+ "TransformContext",
65
+ "TurnEndEvent",
66
+ "TurnStartEvent",
67
+ "agent_loop",
68
+ "agent_loop_continue",
69
+ "default_convert_to_llm",
70
+ "error_result",
71
+ "find_agent_tool",
72
+ ]