ellements 0.2.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 (130) hide show
  1. ellements/__init__.py +57 -0
  2. ellements/agents/__init__.py +45 -0
  3. ellements/agents/backend.py +100 -0
  4. ellements/agents/builder.py +303 -0
  5. ellements/agents/claude_backend.py +200 -0
  6. ellements/agents/controller.py +237 -0
  7. ellements/agents/openai_backend.py +187 -0
  8. ellements/agents/py.typed +0 -0
  9. ellements/agents/runner.py +358 -0
  10. ellements/agents/tools.py +30 -0
  11. ellements/benchmarking/__init__.py +52 -0
  12. ellements/benchmarking/harness.py +342 -0
  13. ellements/benchmarking/py.typed +0 -0
  14. ellements/benchmarking/results.py +173 -0
  15. ellements/cli/__init__.py +80 -0
  16. ellements/cli/adapters.py +73 -0
  17. ellements/cli/agent_tui.py +1178 -0
  18. ellements/cli/components.py +411 -0
  19. ellements/cli/printer.py +229 -0
  20. ellements/cli/py.typed +0 -0
  21. ellements/core/__init__.py +112 -0
  22. ellements/core/async_utils.py +42 -0
  23. ellements/core/budgeting/__init__.py +43 -0
  24. ellements/core/budgeting/client.py +276 -0
  25. ellements/core/budgeting/protocol.py +51 -0
  26. ellements/core/budgeting/trackers.py +177 -0
  27. ellements/core/caching/__init__.py +51 -0
  28. ellements/core/caching/cache.py +73 -0
  29. ellements/core/caching/client.py +300 -0
  30. ellements/core/caching/disk.py +128 -0
  31. ellements/core/caching/keys.py +97 -0
  32. ellements/core/caching/memory.py +104 -0
  33. ellements/core/chunking.py +262 -0
  34. ellements/core/config.py +180 -0
  35. ellements/core/exceptions.py +145 -0
  36. ellements/core/llm/__init__.py +46 -0
  37. ellements/core/llm/client.py +1124 -0
  38. ellements/core/llm/images.py +226 -0
  39. ellements/core/llm/messages.py +202 -0
  40. ellements/core/llm/model_params.py +66 -0
  41. ellements/core/llm/protocol.py +146 -0
  42. ellements/core/llm/requests.py +100 -0
  43. ellements/core/llm/structured.py +91 -0
  44. ellements/core/llm/wrapper.py +79 -0
  45. ellements/core/observability/__init__.py +39 -0
  46. ellements/core/observability/events.py +169 -0
  47. ellements/core/observability/jsonl_logger.py +244 -0
  48. ellements/core/observability/markdown_formatter.py +197 -0
  49. ellements/core/observability/observer.py +56 -0
  50. ellements/core/prompting/__init__.py +14 -0
  51. ellements/core/prompting/context.py +185 -0
  52. ellements/core/prompting/guideline.py +133 -0
  53. ellements/core/prompting/persona.py +267 -0
  54. ellements/core/prompting/sources.py +92 -0
  55. ellements/core/py.typed +0 -0
  56. ellements/core/rate_limit/__init__.py +44 -0
  57. ellements/core/rate_limit/bucket.py +85 -0
  58. ellements/core/rate_limit/client.py +216 -0
  59. ellements/core/rate_limit/protocol.py +27 -0
  60. ellements/core/templating.py +126 -0
  61. ellements/core/tools/__init__.py +51 -0
  62. ellements/core/tools/dialects.py +136 -0
  63. ellements/core/tools/executor.py +48 -0
  64. ellements/core/tools/protocol.py +36 -0
  65. ellements/core/tools/records.py +28 -0
  66. ellements/core/tools/registry.py +205 -0
  67. ellements/core/tools/schemas.py +80 -0
  68. ellements/core/tools/simple.py +119 -0
  69. ellements/core/tools/spec.py +33 -0
  70. ellements/domain_specific/__init__.py +7 -0
  71. ellements/domain_specific/finance/__init__.py +188 -0
  72. ellements/domain_specific/finance/calculations.py +837 -0
  73. ellements/domain_specific/finance/charts.py +426 -0
  74. ellements/domain_specific/finance/portfolio.py +129 -0
  75. ellements/domain_specific/finance/quant_analysis.py +279 -0
  76. ellements/domain_specific/finance/risk.py +362 -0
  77. ellements/domain_specific/finance/technical_indicators.py +241 -0
  78. ellements/domain_specific/finance/tools.py +483 -0
  79. ellements/domain_specific/finance/valuation.py +312 -0
  80. ellements/domain_specific/finance/yahoo_finance.py +1523 -0
  81. ellements/domain_specific/finance/yahoo_finance_models.py +321 -0
  82. ellements/domain_specific/py.typed +0 -0
  83. ellements/execution/__init__.py +56 -0
  84. ellements/execution/callbacks.py +149 -0
  85. ellements/execution/catalog.py +70 -0
  86. ellements/execution/collaborative.py +191 -0
  87. ellements/execution/config.py +135 -0
  88. ellements/execution/py.typed +0 -0
  89. ellements/execution/reflection.py +156 -0
  90. ellements/execution/self_consistency.py +189 -0
  91. ellements/execution/single_call.py +48 -0
  92. ellements/execution/strategies.py +237 -0
  93. ellements/execution/tree_of_thought.py +541 -0
  94. ellements/fslm/__init__.py +108 -0
  95. ellements/fslm/builtins.py +103 -0
  96. ellements/fslm/cli.py +199 -0
  97. ellements/fslm/context.py +50 -0
  98. ellements/fslm/definition.py +163 -0
  99. ellements/fslm/det.py +173 -0
  100. ellements/fslm/dsl.py +458 -0
  101. ellements/fslm/errors.py +38 -0
  102. ellements/fslm/evaluators.py +141 -0
  103. ellements/fslm/kernel.py +603 -0
  104. ellements/fslm/loading.py +123 -0
  105. ellements/fslm/models.py +623 -0
  106. ellements/fslm/nl.py +87 -0
  107. ellements/fslm/observers.py +107 -0
  108. ellements/fslm/persistence.py +72 -0
  109. ellements/fslm/py.typed +0 -0
  110. ellements/fslm/rendering.py +551 -0
  111. ellements/fslm/visualization.py +25 -0
  112. ellements/reporting/__init__.py +12 -0
  113. ellements/reporting/charts.py +364 -0
  114. ellements/reporting/html_generation.py +132 -0
  115. ellements/reporting/py.typed +0 -0
  116. ellements/reporting/visualization.py +73 -0
  117. ellements/standard_tools/__init__.py +22 -0
  118. ellements/standard_tools/py.typed +0 -0
  119. ellements/standard_tools/terminal.py +205 -0
  120. ellements/standard_tools/web/__init__.py +37 -0
  121. ellements/standard_tools/web/browser_viewer.py +214 -0
  122. ellements/standard_tools/web/crawler.py +454 -0
  123. ellements/standard_tools/web/search.py +399 -0
  124. ellements/standard_tools/web/youtube.py +1297 -0
  125. ellements-0.2.0.dist-info/METADATA +368 -0
  126. ellements-0.2.0.dist-info/RECORD +130 -0
  127. ellements-0.2.0.dist-info/WHEEL +5 -0
  128. ellements-0.2.0.dist-info/entry_points.txt +2 -0
  129. ellements-0.2.0.dist-info/licenses/LICENSE +42 -0
  130. ellements-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,541 @@
1
+ """Tree-of-thought strategy — three search modes over one strategy.
2
+
3
+ Implements three variants behind a single :class:`TreeOfThoughtStrategy`
4
+ selected via the ``mode`` config field:
5
+
6
+ - ``"beam"`` (default): canonical BFS with step-level beam search
7
+ (Yao et al., 2023). Required prompts: ``thought_step``,
8
+ ``evaluate_step``, ``synthesize``.
9
+ - ``"dfs"``: depth-first with backtracking + early exit on max-scoring
10
+ leaf. Same required prompts as ``"beam"``.
11
+ - ``"simple"``: simplified flat search — generate N complete solutions,
12
+ evaluate them together, synthesize the best. Required prompts:
13
+ ``generate``, ``evaluate``, ``synthesize``.
14
+
15
+ All evaluations use a structured :class:`Evaluation` with a numeric
16
+ ``score`` (0.0 – 1.0) and short ``reasoning`` — no keyword scanning.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import asyncio
22
+ import logging
23
+ from collections.abc import Mapping
24
+ from typing import Any
25
+
26
+ from ellements.core import LLMClient
27
+ from pydantic import BaseModel, Field
28
+
29
+ from .config import StrategyConfigInput, TreeOfThoughtConfig
30
+ from .strategies import BaseStrategy, StepRecord, StrategyResult
31
+
32
+ _logger = logging.getLogger(__name__)
33
+
34
+
35
+ class Evaluation(BaseModel):
36
+ """Structured evaluation produced by the ``evaluate`` stage."""
37
+
38
+ score: float = Field(
39
+ ge=0.0,
40
+ le=1.0,
41
+ description="Quality score in [0.0, 1.0]; higher is better",
42
+ )
43
+ reasoning: str = Field(
44
+ default="",
45
+ description="Short justification for the score",
46
+ )
47
+
48
+
49
+ class TreeOfThoughtStrategy(BaseStrategy):
50
+ """Tree-of-Thought reasoning with selectable search mode."""
51
+
52
+ async def execute(
53
+ self,
54
+ prompts: Mapping[str, str],
55
+ client: LLMClient,
56
+ tools: list[dict[str, Any]] | Mapping[str, Any] | None = None,
57
+ config: StrategyConfigInput = None,
58
+ ) -> StrategyResult:
59
+ typed_config = self._normalize_config(config, TreeOfThoughtConfig)
60
+ if typed_config.mode == "simple":
61
+ return await self._execute_simple(prompts, client, typed_config, tools)
62
+ if typed_config.mode == "dfs":
63
+ return await self._execute_dfs(prompts, client, typed_config, tools)
64
+ return await self._execute_beam(prompts, client, typed_config, tools)
65
+
66
+ # ── beam (BFS) ──────────────────────────────────────────────────
67
+
68
+ async def _execute_beam(
69
+ self,
70
+ prompts: Mapping[str, str],
71
+ client: LLMClient,
72
+ config: TreeOfThoughtConfig,
73
+ tools: list[dict[str, Any]] | Mapping[str, Any] | None,
74
+ ) -> StrategyResult:
75
+ system = prompts.get("system")
76
+ sem = asyncio.Semaphore(config.max_concurrent)
77
+ steps: list[StepRecord] = []
78
+
79
+ thought_template = self._get_prompt(prompts, "thought_step")
80
+ eval_template = self._get_prompt(prompts, "evaluate_step")
81
+
82
+ thought_temp = self._stage_temperature(
83
+ config, "thought", default=config.thought_temperature
84
+ )
85
+ evaluate_temp = self._stage_temperature(
86
+ config, "evaluate", default=config.evaluate_temperature
87
+ )
88
+
89
+ states: list[str] = [""]
90
+
91
+ for depth in range(config.max_depth):
92
+ candidates: list[tuple[str, float]] = []
93
+
94
+ for state_idx, state in enumerate(states):
95
+ thoughts_prompt = self._render_template(
96
+ thought_template, {"state": state}
97
+ )
98
+ thoughts = await asyncio.gather(
99
+ *(
100
+ self._guarded_complete(
101
+ sem,
102
+ client,
103
+ thoughts_prompt,
104
+ config=config,
105
+ temperature=thought_temp,
106
+ system=system,
107
+ tools=tools,
108
+ )
109
+ for _ in range(config.branching_factor)
110
+ )
111
+ )
112
+
113
+ for t_idx, thought in enumerate(thoughts):
114
+ new_state = self._record_thought(
115
+ thought=thought,
116
+ state=state,
117
+ depth=depth,
118
+ step_name=f"thought_d{depth}_s{state_idx}_b{t_idx}",
119
+ step_metadata={
120
+ "depth": depth,
121
+ "state_idx": state_idx,
122
+ "branch": t_idx,
123
+ },
124
+ steps=steps,
125
+ config=config,
126
+ )
127
+ evaluation = await self._evaluate_state(
128
+ eval_template=eval_template,
129
+ state=new_state,
130
+ sem=sem,
131
+ client=client,
132
+ config=config,
133
+ evaluate_temp=evaluate_temp,
134
+ system=system,
135
+ steps=steps,
136
+ step_name=f"eval_d{depth}_s{state_idx}_b{t_idx}",
137
+ step_metadata={"depth": depth},
138
+ )
139
+ if evaluation.score > 0:
140
+ candidates.append((new_state, evaluation.score))
141
+
142
+ if not candidates:
143
+ _logger.warning(
144
+ "No viable candidates at depth %d, stopping early", depth
145
+ )
146
+ break
147
+
148
+ candidates.sort(key=lambda item: item[1], reverse=True)
149
+ states = [state for state, _ in candidates[: config.beam_width]]
150
+
151
+ best_path = states[0] if states else ""
152
+ synth_steps = await self._synthesize(
153
+ client,
154
+ prompts,
155
+ best_path,
156
+ config=config,
157
+ system=system,
158
+ tools=tools,
159
+ )
160
+ steps.extend(synth_steps)
161
+ for step in synth_steps:
162
+ self._notify_step(config, step)
163
+
164
+ return StrategyResult(
165
+ output=synth_steps[-1].response if synth_steps else "",
166
+ steps=steps,
167
+ metadata={
168
+ "mode": "beam",
169
+ "max_depth": config.max_depth,
170
+ "beam_width": config.beam_width,
171
+ "branching_factor": config.branching_factor,
172
+ },
173
+ )
174
+
175
+ # ── dfs ─────────────────────────────────────────────────────────
176
+
177
+ async def _execute_dfs(
178
+ self,
179
+ prompts: Mapping[str, str],
180
+ client: LLMClient,
181
+ config: TreeOfThoughtConfig,
182
+ tools: list[dict[str, Any]] | Mapping[str, Any] | None,
183
+ ) -> StrategyResult:
184
+ system = prompts.get("system")
185
+ sem = asyncio.Semaphore(config.max_concurrent)
186
+ steps: list[StepRecord] = []
187
+
188
+ thought_template = self._get_prompt(prompts, "thought_step")
189
+ eval_template = self._get_prompt(prompts, "evaluate_step")
190
+
191
+ thought_temp = self._stage_temperature(
192
+ config, "thought", default=config.thought_temperature
193
+ )
194
+ evaluate_temp = self._stage_temperature(
195
+ config, "evaluate", default=config.evaluate_temperature
196
+ )
197
+
198
+ best_state: str | None = None
199
+ best_score: float = -1.0
200
+
201
+ async def dfs(state: str, depth: int) -> None:
202
+ nonlocal best_state, best_score
203
+
204
+ if depth >= config.max_depth:
205
+ evaluation = await self._evaluate_state(
206
+ eval_template=eval_template,
207
+ state=state,
208
+ sem=sem,
209
+ client=client,
210
+ config=config,
211
+ evaluate_temp=evaluate_temp,
212
+ system=system,
213
+ steps=steps,
214
+ step_name=f"eval_leaf_d{depth}",
215
+ step_metadata={"depth": depth, "leaf": True},
216
+ )
217
+ if evaluation.score > best_score:
218
+ best_score = evaluation.score
219
+ best_state = state
220
+ return
221
+
222
+ thoughts_prompt = self._render_template(
223
+ thought_template, {"state": state}
224
+ )
225
+ thoughts = await asyncio.gather(
226
+ *(
227
+ self._guarded_complete(
228
+ sem,
229
+ client,
230
+ thoughts_prompt,
231
+ config=config,
232
+ temperature=thought_temp,
233
+ system=system,
234
+ tools=tools,
235
+ )
236
+ for _ in range(config.branching_factor)
237
+ )
238
+ )
239
+
240
+ for t_idx, thought in enumerate(thoughts):
241
+ new_state = self._record_thought(
242
+ thought=thought,
243
+ state=state,
244
+ depth=depth,
245
+ step_name=f"thought_d{depth}_b{t_idx}",
246
+ step_metadata={"depth": depth, "branch": t_idx},
247
+ steps=steps,
248
+ config=config,
249
+ )
250
+ evaluation = await self._evaluate_state(
251
+ eval_template=eval_template,
252
+ state=new_state,
253
+ sem=sem,
254
+ client=client,
255
+ config=config,
256
+ evaluate_temp=evaluate_temp,
257
+ system=system,
258
+ steps=steps,
259
+ step_name=f"eval_d{depth}_b{t_idx}",
260
+ step_metadata={"depth": depth},
261
+ )
262
+
263
+ if evaluation.score <= 0:
264
+ continue
265
+
266
+ await dfs(new_state, depth + 1)
267
+ if best_score >= 1.0:
268
+ return
269
+
270
+ await dfs("", 0)
271
+
272
+ synth_steps = await self._synthesize(
273
+ client,
274
+ prompts,
275
+ best_state or "",
276
+ config=config,
277
+ system=system,
278
+ tools=tools,
279
+ )
280
+ steps.extend(synth_steps)
281
+ for step in synth_steps:
282
+ self._notify_step(config, step)
283
+
284
+ return StrategyResult(
285
+ output=synth_steps[-1].response if synth_steps else "",
286
+ steps=steps,
287
+ metadata={
288
+ "mode": "dfs",
289
+ "max_depth": config.max_depth,
290
+ "branching_factor": config.branching_factor,
291
+ "best_score": best_score,
292
+ },
293
+ )
294
+
295
+ # ── simple (flat) ───────────────────────────────────────────────
296
+
297
+ async def _execute_simple(
298
+ self,
299
+ prompts: Mapping[str, str],
300
+ client: LLMClient,
301
+ config: TreeOfThoughtConfig,
302
+ tools: list[dict[str, Any]] | Mapping[str, Any] | None,
303
+ ) -> StrategyResult:
304
+ system = prompts.get("system")
305
+ sem = asyncio.Semaphore(config.max_concurrent)
306
+ steps: list[StepRecord] = []
307
+
308
+ generate_template = self._get_prompt(prompts, "generate")
309
+ evaluate_template = self._get_prompt(prompts, "evaluate")
310
+ synthesize_template = self._get_prompt(prompts, "synthesize")
311
+
312
+ thought_temp = self._stage_temperature(
313
+ config, "generate", default=config.thought_temperature
314
+ )
315
+ evaluate_temp = self._stage_temperature(
316
+ config, "evaluate", default=config.evaluate_temperature
317
+ )
318
+ synthesize_temp = self._stage_temperature(
319
+ config, "synthesize", default=config.synthesize_temperature
320
+ )
321
+
322
+ async def _gen_one() -> str:
323
+ async with sem:
324
+ return await self._complete(
325
+ client,
326
+ generate_template,
327
+ config=config,
328
+ temperature=thought_temp,
329
+ system=system,
330
+ tools=tools,
331
+ )
332
+
333
+ generated = await asyncio.gather(
334
+ *(_gen_one() for _ in range(config.branching_factor))
335
+ )
336
+ for i, resp in enumerate(generated):
337
+ steps.append(
338
+ StepRecord(
339
+ name=f"generate_{i}",
340
+ prompt_key="generate",
341
+ response=resp,
342
+ metadata={"branch": i},
343
+ )
344
+ )
345
+ self._notify_step(config, steps[-1])
346
+
347
+ candidates_text = "\n\n".join(
348
+ f"--- Path {i + 1} ---\n{resp}" for i, resp in enumerate(generated)
349
+ )
350
+ eval_prompt = self._render_template(
351
+ evaluate_template, {"candidates": candidates_text}
352
+ )
353
+ evaluation = await self._guarded_evaluate(
354
+ sem,
355
+ client,
356
+ eval_prompt,
357
+ config=config,
358
+ temperature=evaluate_temp,
359
+ system=system,
360
+ )
361
+ steps.append(
362
+ StepRecord(
363
+ name="evaluate",
364
+ prompt_key="evaluate",
365
+ response=evaluation.model_dump_json(),
366
+ metadata={"score": evaluation.score},
367
+ )
368
+ )
369
+ self._notify_step(config, steps[-1])
370
+
371
+ synth_prompt = self._render_template(
372
+ synthesize_template,
373
+ {
374
+ "candidates": candidates_text,
375
+ "evaluation": evaluation.reasoning,
376
+ "best_approach": evaluation.reasoning,
377
+ },
378
+ )
379
+ synthesis = await self._complete(
380
+ client,
381
+ synth_prompt,
382
+ config=config,
383
+ temperature=synthesize_temp,
384
+ system=system,
385
+ tools=tools,
386
+ )
387
+ steps.append(
388
+ StepRecord(
389
+ name="synthesize", prompt_key="synthesize", response=synthesis
390
+ )
391
+ )
392
+ self._notify_step(config, steps[-1])
393
+
394
+ return StrategyResult(
395
+ output=synthesis,
396
+ steps=steps,
397
+ metadata={
398
+ "mode": "simple",
399
+ "branching_factor": config.branching_factor,
400
+ },
401
+ )
402
+
403
+ # ── shared helpers ──────────────────────────────────────────────
404
+
405
+ def _record_thought(
406
+ self,
407
+ *,
408
+ thought: str,
409
+ state: str,
410
+ depth: int,
411
+ step_name: str,
412
+ step_metadata: dict[str, Any],
413
+ steps: list[StepRecord],
414
+ config: TreeOfThoughtConfig,
415
+ ) -> str:
416
+ """Append a ``thought_step`` record and return the extended state.
417
+
418
+ Shared by ``_execute_beam`` and ``_execute_dfs`` so they don't
419
+ each open-code the StepRecord/notify dance after every thought.
420
+ """
421
+ new_state = f"{state}\n\nStep {depth + 1}: {thought}".strip()
422
+ steps.append(
423
+ StepRecord(
424
+ name=step_name,
425
+ prompt_key="thought_step",
426
+ response=thought,
427
+ metadata=step_metadata,
428
+ )
429
+ )
430
+ self._notify_step(config, steps[-1])
431
+ return new_state
432
+
433
+ async def _evaluate_state(
434
+ self,
435
+ *,
436
+ eval_template: str,
437
+ state: str,
438
+ sem: asyncio.Semaphore,
439
+ client: LLMClient,
440
+ config: TreeOfThoughtConfig,
441
+ evaluate_temp: float,
442
+ system: str | None,
443
+ steps: list[StepRecord],
444
+ step_name: str,
445
+ step_metadata: dict[str, Any],
446
+ ) -> Evaluation:
447
+ """Score *state* and append the matching ``evaluate_step`` record."""
448
+ eval_prompt = self._render_template(eval_template, {"state": state})
449
+ evaluation = await self._guarded_evaluate(
450
+ sem,
451
+ client,
452
+ eval_prompt,
453
+ config=config,
454
+ temperature=evaluate_temp,
455
+ system=system,
456
+ )
457
+ steps.append(
458
+ StepRecord(
459
+ name=step_name,
460
+ prompt_key="evaluate_step",
461
+ response=evaluation.model_dump_json(),
462
+ metadata={**step_metadata, "score": evaluation.score},
463
+ )
464
+ )
465
+ self._notify_step(config, steps[-1])
466
+ return evaluation
467
+
468
+ async def _synthesize(
469
+ self,
470
+ client: LLMClient,
471
+ prompts: Mapping[str, str],
472
+ best_path: str,
473
+ *,
474
+ config: TreeOfThoughtConfig,
475
+ system: str | None,
476
+ tools: list[dict[str, Any]] | Mapping[str, Any] | None,
477
+ ) -> list[StepRecord]:
478
+ template = self._get_prompt(prompts, "synthesize")
479
+ synth_prompt = self._render_template(template, {"best_path": best_path})
480
+ synthesize_temp = self._stage_temperature(
481
+ config, "synthesize", default=config.synthesize_temperature
482
+ )
483
+ response = await self._complete(
484
+ client,
485
+ synth_prompt,
486
+ config=config,
487
+ temperature=synthesize_temp,
488
+ system=system,
489
+ tools=tools,
490
+ )
491
+ return [
492
+ StepRecord(
493
+ name="synthesize", prompt_key="synthesize", response=response
494
+ )
495
+ ]
496
+
497
+ @classmethod
498
+ async def _guarded_complete(
499
+ cls,
500
+ sem: asyncio.Semaphore,
501
+ client: LLMClient,
502
+ prompt: str,
503
+ *,
504
+ config: TreeOfThoughtConfig,
505
+ temperature: float,
506
+ system: str | None,
507
+ tools: list[dict[str, Any]] | Mapping[str, Any] | None,
508
+ ) -> str:
509
+ async with sem:
510
+ return await cls._complete(
511
+ client,
512
+ prompt,
513
+ config=config,
514
+ temperature=temperature,
515
+ system=system,
516
+ tools=tools,
517
+ )
518
+
519
+ @classmethod
520
+ async def _guarded_evaluate(
521
+ cls,
522
+ sem: asyncio.Semaphore,
523
+ client: LLMClient,
524
+ prompt: str,
525
+ *,
526
+ config: TreeOfThoughtConfig,
527
+ temperature: float,
528
+ system: str | None,
529
+ ) -> Evaluation:
530
+ async with sem:
531
+ return await cls._complete_structured(
532
+ client,
533
+ prompt,
534
+ response_model=Evaluation,
535
+ config=config,
536
+ temperature=temperature,
537
+ system=system,
538
+ )
539
+
540
+
541
+ __all__ = ["Evaluation", "TreeOfThoughtStrategy"]
@@ -0,0 +1,108 @@
1
+ """Agentic finite-state linguistic machines for ellements."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from . import det, nl
6
+ from .context import FSLMContext
7
+ from .definition import MachineDefinition, RuntimeBindings
8
+ from .dsl import MachineBuilder, StateBuilder, TransitionBuilder, machine
9
+ from .errors import (
10
+ BudgetExhaustedError,
11
+ FSLMError,
12
+ InvalidTransitionError,
13
+ InvariantViolationError,
14
+ SafetyBlockedError,
15
+ SpecValidationError,
16
+ )
17
+ from .evaluators import LLMDecisionEvaluator
18
+ from .kernel import ActionExecutor, FSLMKernel, GuardEvaluator, InvariantChecker
19
+ from .loading import load_machine_definition, load_machine_spec
20
+ from .models import (
21
+ ActionResult,
22
+ ActionSpec,
23
+ AffordanceSpec,
24
+ BudgetSpec,
25
+ ConfidencePolicy,
26
+ DecisionResult,
27
+ EffectSpec,
28
+ EventPatternSpec,
29
+ ExecutionPolicy,
30
+ FSLMEvent,
31
+ GuardSpec,
32
+ InvariantSpec,
33
+ MachineSnapshot,
34
+ MachineSpec,
35
+ OutputRecord,
36
+ OutputSpec,
37
+ StateSpec,
38
+ StepResult,
39
+ ToolRef,
40
+ TransitionSpec,
41
+ )
42
+ from .observers import (
43
+ FSLMEventRecord,
44
+ FSLMObserver,
45
+ JsonlFSLMObserver,
46
+ RecordingFSLMObserver,
47
+ RichConsoleFSLMObserver,
48
+ )
49
+ from .persistence import InMemoryFSLMStore, LocalFSLMStore
50
+ from .rendering import make_console, render_snapshot, render_step, render_validation
51
+ from .visualization import to_mermaid
52
+
53
+ __all__ = [
54
+ "ActionExecutor",
55
+ "ActionResult",
56
+ "ActionSpec",
57
+ "AffordanceSpec",
58
+ "BudgetExhaustedError",
59
+ "BudgetSpec",
60
+ "ConfidencePolicy",
61
+ "DecisionResult",
62
+ "EventPatternSpec",
63
+ "ExecutionPolicy",
64
+ "EffectSpec",
65
+ "FSLMContext",
66
+ "FSLMError",
67
+ "FSLMEvent",
68
+ "FSLMEventRecord",
69
+ "FSLMKernel",
70
+ "FSLMObserver",
71
+ "GuardEvaluator",
72
+ "GuardSpec",
73
+ "InMemoryFSLMStore",
74
+ "InvalidTransitionError",
75
+ "InvariantChecker",
76
+ "InvariantSpec",
77
+ "InvariantViolationError",
78
+ "JsonlFSLMObserver",
79
+ "LocalFSLMStore",
80
+ "LLMDecisionEvaluator",
81
+ "MachineBuilder",
82
+ "MachineDefinition",
83
+ "MachineSnapshot",
84
+ "MachineSpec",
85
+ "OutputRecord",
86
+ "OutputSpec",
87
+ "RecordingFSLMObserver",
88
+ "RichConsoleFSLMObserver",
89
+ "RuntimeBindings",
90
+ "SafetyBlockedError",
91
+ "SpecValidationError",
92
+ "StateBuilder",
93
+ "StateSpec",
94
+ "StepResult",
95
+ "ToolRef",
96
+ "TransitionBuilder",
97
+ "TransitionSpec",
98
+ "det",
99
+ "load_machine_definition",
100
+ "machine",
101
+ "make_console",
102
+ "load_machine_spec",
103
+ "nl",
104
+ "render_snapshot",
105
+ "render_step",
106
+ "render_validation",
107
+ "to_mermaid",
108
+ ]