flock-core 0.2.14__py3-none-any.whl → 0.2.15__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.
Potentially problematic release.
This version of flock-core might be problematic. Click here for more details.
- flock/__init__.py +6 -0
- flock/cli/constants.py +1 -0
- flock/config.py +0 -1
- flock/core/execution/local_executor.py +7 -3
- flock/core/execution/temporal_executor.py +1 -8
- flock/core/flock.py +4 -16
- flock/core/flock_agent.py +41 -0
- flock/core/logging/formatters/enum_builder.py +38 -0
- flock/core/logging/formatters/theme_builder.py +2 -6
- flock/core/logging/formatters/themed_formatter.py +127 -19
- flock/core/logging/formatters/themes.py +340 -0
- flock/core/logging/telemetry.py +1 -1
- flock/workflow/activities.py +1 -18
- {flock_core-0.2.14.dist-info → flock_core-0.2.15.dist-info}/METADATA +1 -1
- {flock_core-0.2.14.dist-info → flock_core-0.2.15.dist-info}/RECORD +18 -22
- flock/cli/examples/chatty.flock +0 -1
- flock/cli/examples/chatty.json +0 -1
- flock/core/logging/formatters/base_formatter.py +0 -36
- flock/core/logging/formatters/formatter_factory.py +0 -38
- flock/core/logging/formatters/pprint_formatter.py +0 -31
- flock/core/logging/formatters/rich_formatters.py +0 -132
- {flock_core-0.2.14.dist-info → flock_core-0.2.15.dist-info}/WHEEL +0 -0
- {flock_core-0.2.14.dist-info → flock_core-0.2.15.dist-info}/entry_points.txt +0 -0
- {flock_core-0.2.14.dist-info → flock_core-0.2.15.dist-info}/licenses/LICENSE +0 -0
flock/__init__.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"""Flock package initialization."""
|
|
2
2
|
|
|
3
|
+
from flock.cli.constants import CLI_THEME_BUILDER
|
|
4
|
+
from flock.core.logging.formatters.theme_builder import theme_builder
|
|
5
|
+
|
|
3
6
|
|
|
4
7
|
def main():
|
|
5
8
|
"""Main function."""
|
|
@@ -35,6 +38,7 @@ def main():
|
|
|
35
38
|
CLI_LOAD_FLOCK,
|
|
36
39
|
# CLI_LOAD_EXAMPLE,
|
|
37
40
|
questionary.Separator(),
|
|
41
|
+
CLI_THEME_BUILDER,
|
|
38
42
|
CLI_SETTINGS,
|
|
39
43
|
questionary.Separator(),
|
|
40
44
|
CLI_START_ADVANCED_MODE,
|
|
@@ -45,6 +49,8 @@ def main():
|
|
|
45
49
|
|
|
46
50
|
if result == CLI_LOAD_FLOCK:
|
|
47
51
|
load_flock()
|
|
52
|
+
if result == CLI_THEME_BUILDER:
|
|
53
|
+
theme_builder()
|
|
48
54
|
|
|
49
55
|
|
|
50
56
|
if __name__ == "__main__":
|
flock/cli/constants.py
CHANGED
|
@@ -4,6 +4,7 @@ CLI_CREATE_AGENT = "Create an agent"
|
|
|
4
4
|
CLI_CREATE_FLOCK = "Create a flock"
|
|
5
5
|
CLI_LOAD_AGENT = "Load an agent"
|
|
6
6
|
CLI_LOAD_FLOCK = "Load a *.flock file"
|
|
7
|
+
CLI_THEME_BUILDER = "Theme builder"
|
|
7
8
|
CLI_LOAD_EXAMPLE = "Load a example"
|
|
8
9
|
CLI_SETTINGS = "Settings"
|
|
9
10
|
CLI_START_ADVANCED_MODE = "Start advanced mode (coming soon)"
|
flock/config.py
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# src/your_package/core/execution/local_executor.py
|
|
2
2
|
from flock.core.context.context import FlockContext
|
|
3
3
|
from flock.core.logging.logging import get_logger
|
|
4
|
-
from flock.workflow.activities import
|
|
4
|
+
from flock.workflow.activities import (
|
|
5
|
+
run_agent, # This should be the local activity function
|
|
6
|
+
)
|
|
5
7
|
|
|
6
8
|
logger = get_logger("flock")
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
async def run_local_workflow(
|
|
11
|
+
async def run_local_workflow(
|
|
12
|
+
context: FlockContext, box_result: bool = True
|
|
13
|
+
) -> dict:
|
|
10
14
|
"""Execute the agent workflow locally (for debugging).
|
|
11
15
|
|
|
12
16
|
Args:
|
|
@@ -18,7 +22,7 @@ async def run_local_workflow(context: FlockContext, output_formatter, box_result
|
|
|
18
22
|
A dictionary containing the workflow result.
|
|
19
23
|
"""
|
|
20
24
|
logger.info("Running local debug workflow")
|
|
21
|
-
result = await run_agent(context
|
|
25
|
+
result = await run_agent(context)
|
|
22
26
|
if box_result:
|
|
23
27
|
from box import Box
|
|
24
28
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# src/your_package/core/execution/temporal_executor.py
|
|
2
|
-
from devtools import pprint
|
|
3
2
|
|
|
4
3
|
from flock.core.context.context import FlockContext
|
|
5
4
|
from flock.core.context.context_vars import FLOCK_RUN_ID
|
|
6
|
-
from flock.core.logging.formatters.formatter_factory import FormatterFactory
|
|
7
5
|
from flock.core.logging.logging import get_logger
|
|
8
6
|
from flock.workflow.activities import (
|
|
9
7
|
run_agent, # Activity function used in Temporal
|
|
@@ -16,7 +14,6 @@ logger = get_logger("flock")
|
|
|
16
14
|
|
|
17
15
|
async def run_temporal_workflow(
|
|
18
16
|
context: FlockContext,
|
|
19
|
-
output_formatter,
|
|
20
17
|
box_result: bool = True,
|
|
21
18
|
) -> dict:
|
|
22
19
|
"""Execute the agent workflow via Temporal for robust, distributed processing.
|
|
@@ -43,11 +40,7 @@ async def run_temporal_workflow(
|
|
|
43
40
|
|
|
44
41
|
agent_name = context.get_variable("FLOCK_CURRENT_AGENT")
|
|
45
42
|
logger.debug("Formatting Temporal result", agent=agent_name)
|
|
46
|
-
|
|
47
|
-
formatter = FormatterFactory.create_formatter(output_formatter)
|
|
48
|
-
formatter.display(result, agent_name, output_formatter.wait_for_input)
|
|
49
|
-
else:
|
|
50
|
-
pprint(result)
|
|
43
|
+
|
|
51
44
|
if box_result:
|
|
52
45
|
from box import Box
|
|
53
46
|
|
flock/core/flock.py
CHANGED
|
@@ -10,13 +10,12 @@ import cloudpickle
|
|
|
10
10
|
from opentelemetry import trace
|
|
11
11
|
from opentelemetry.baggage import get_baggage, set_baggage
|
|
12
12
|
|
|
13
|
+
from flock.config import TELEMETRY
|
|
13
14
|
from flock.core.context.context import FlockContext
|
|
14
15
|
from flock.core.context.context_manager import initialize_context
|
|
15
16
|
from flock.core.execution.local_executor import run_local_workflow
|
|
16
17
|
from flock.core.execution.temporal_executor import run_temporal_workflow
|
|
17
18
|
from flock.core.flock_agent import FlockAgent
|
|
18
|
-
from flock.core.logging.formatters.base_formatter import FormatterOptions
|
|
19
|
-
from flock.core.logging.formatters.pprint_formatter import PrettyPrintFormatter
|
|
20
19
|
from flock.core.logging.logging import get_logger
|
|
21
20
|
from flock.core.registry.agent_registry import Registry
|
|
22
21
|
from flock.core.util.cli_helper import display_banner
|
|
@@ -24,7 +23,7 @@ from flock.core.util.input_resolver import top_level_to_keys
|
|
|
24
23
|
|
|
25
24
|
T = TypeVar("T", bound=FlockAgent)
|
|
26
25
|
logger = get_logger("flock")
|
|
27
|
-
|
|
26
|
+
TELEMETRY.setup_tracing()
|
|
28
27
|
tracer = trace.get_tracer(__name__)
|
|
29
28
|
|
|
30
29
|
|
|
@@ -40,9 +39,6 @@ class Flock:
|
|
|
40
39
|
model: str = "openai/gpt-4o",
|
|
41
40
|
local_debug: bool = False,
|
|
42
41
|
enable_logging: bool = False,
|
|
43
|
-
output_formatter: FormatterOptions = FormatterOptions(
|
|
44
|
-
PrettyPrintFormatter
|
|
45
|
-
),
|
|
46
42
|
show_cli_banner: bool = True,
|
|
47
43
|
):
|
|
48
44
|
"""Initialize the Flock orchestrator.
|
|
@@ -57,9 +53,6 @@ class Flock:
|
|
|
57
53
|
span.set_attribute("model", model)
|
|
58
54
|
span.set_attribute("local_debug", local_debug)
|
|
59
55
|
span.set_attribute("enable_logging", enable_logging)
|
|
60
|
-
span.set_attribute(
|
|
61
|
-
"output_formatter", output_formatter.formatter.__name__
|
|
62
|
-
)
|
|
63
56
|
logger.info(
|
|
64
57
|
"Initializing Flock",
|
|
65
58
|
model=model,
|
|
@@ -80,7 +73,6 @@ class Flock:
|
|
|
80
73
|
self.context = FlockContext()
|
|
81
74
|
self.model = model
|
|
82
75
|
self.local_debug = local_debug
|
|
83
|
-
self.output_formatter = output_formatter
|
|
84
76
|
self.start_agent: FlockAgent | str | None = None
|
|
85
77
|
self.input: dict = {}
|
|
86
78
|
|
|
@@ -410,13 +402,9 @@ class Flock:
|
|
|
410
402
|
)
|
|
411
403
|
|
|
412
404
|
if self.local_debug:
|
|
413
|
-
return await run_local_workflow(
|
|
414
|
-
self.context, self.output_formatter, box_result
|
|
415
|
-
)
|
|
405
|
+
return await run_local_workflow(self.context, box_result)
|
|
416
406
|
else:
|
|
417
|
-
return await run_temporal_workflow(
|
|
418
|
-
self.context, self.output_formatter, box_result
|
|
419
|
-
)
|
|
407
|
+
return await run_temporal_workflow(self.context, box_result)
|
|
420
408
|
except Exception as e:
|
|
421
409
|
logger.exception("Execution failed", error=str(e))
|
|
422
410
|
raise
|
flock/core/flock_agent.py
CHANGED
|
@@ -12,6 +12,10 @@ import cloudpickle
|
|
|
12
12
|
from pydantic import BaseModel, Field
|
|
13
13
|
|
|
14
14
|
from flock.core.context.context import FlockContext
|
|
15
|
+
from flock.core.logging.formatters.themed_formatter import (
|
|
16
|
+
ThemedAgentResultFormatter,
|
|
17
|
+
)
|
|
18
|
+
from flock.core.logging.formatters.themes import OutputTheme
|
|
15
19
|
from flock.core.logging.logging import get_logger
|
|
16
20
|
from flock.core.mixin.dspy_integration import AgentType, DSPyIntegrationMixin
|
|
17
21
|
from flock.core.mixin.prompt_parser import PromptParserMixin
|
|
@@ -48,6 +52,25 @@ class FlockAgentConfig:
|
|
|
48
52
|
)
|
|
49
53
|
|
|
50
54
|
|
|
55
|
+
@dataclass
|
|
56
|
+
class FlockAgentOutputConfig:
|
|
57
|
+
"""Configuration options for a FlockAgent."""
|
|
58
|
+
|
|
59
|
+
render_table: bool = field(
|
|
60
|
+
default=False, metadata={"description": "Renders a table."}
|
|
61
|
+
)
|
|
62
|
+
theme: OutputTheme = field( # type: ignore
|
|
63
|
+
default=OutputTheme.afterglow,
|
|
64
|
+
metadata={"description": "Disables the agent's output."},
|
|
65
|
+
)
|
|
66
|
+
max_length: int = field(
|
|
67
|
+
default=1000, metadata={"description": "Disables the agent's output."}
|
|
68
|
+
)
|
|
69
|
+
wait_for_input: bool = field(
|
|
70
|
+
default=False, metadata={"description": "Wait for input."}
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
51
74
|
@dataclass
|
|
52
75
|
class HandOff:
|
|
53
76
|
"""Base class for handoff returns."""
|
|
@@ -186,6 +209,11 @@ class FlockAgent(BaseModel, ABC, PromptParserMixin, DSPyIntegrationMixin):
|
|
|
186
209
|
description="Configuration options for the agent, such as serialization settings.",
|
|
187
210
|
)
|
|
188
211
|
|
|
212
|
+
output_config: FlockAgentOutputConfig = Field(
|
|
213
|
+
default_factory=FlockAgentOutputConfig,
|
|
214
|
+
description="Configuration options for the agent's output.",
|
|
215
|
+
)
|
|
216
|
+
|
|
189
217
|
# Lifecycle callback fields: if provided, these callbacks are used instead of overriding the methods.
|
|
190
218
|
initialize_callback: Callable[[dict[str, Any]], Awaitable[None]] | None = (
|
|
191
219
|
Field(
|
|
@@ -414,6 +442,7 @@ class FlockAgent(BaseModel, ABC, PromptParserMixin, DSPyIntegrationMixin):
|
|
|
414
442
|
try:
|
|
415
443
|
await self.initialize(inputs)
|
|
416
444
|
result = await self.evaluate(inputs)
|
|
445
|
+
self.display_output(result)
|
|
417
446
|
await self.terminate(inputs, result)
|
|
418
447
|
span.set_attribute("result", str(result))
|
|
419
448
|
logger.info("Agent run completed", agent=self.name)
|
|
@@ -426,6 +455,18 @@ class FlockAgent(BaseModel, ABC, PromptParserMixin, DSPyIntegrationMixin):
|
|
|
426
455
|
span.record_exception(run_error)
|
|
427
456
|
raise
|
|
428
457
|
|
|
458
|
+
def display_info(self) -> None:
|
|
459
|
+
pass
|
|
460
|
+
|
|
461
|
+
def display_output(self, result: dict[str, Any]) -> None:
|
|
462
|
+
"""Display the agent's output using the configured output formatter."""
|
|
463
|
+
ThemedAgentResultFormatter(
|
|
464
|
+
self.output_config.theme,
|
|
465
|
+
self.output_config.max_length,
|
|
466
|
+
self.output_config.render_table,
|
|
467
|
+
self.output_config.wait_for_input,
|
|
468
|
+
).display_result(result, self.name)
|
|
469
|
+
|
|
429
470
|
async def run_temporal(self, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
430
471
|
"""Execute this agent via a Temporal workflow for enhanced fault tolerance and asynchronous processing.
|
|
431
472
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Enum Builder."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import pathlib
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
theme_folder = pathlib.Path(__file__).parent.parent.parent.parent / "themes"
|
|
8
|
+
|
|
9
|
+
if not theme_folder.exists():
|
|
10
|
+
raise FileNotFoundError(f"Theme folder not found: {theme_folder}")
|
|
11
|
+
|
|
12
|
+
theme_files = [
|
|
13
|
+
pathlib.Path(f.path).stem for f in os.scandir(theme_folder) if f.is_file()
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
theme_enum_entries = {}
|
|
17
|
+
for theme in theme_files:
|
|
18
|
+
safe_name = (
|
|
19
|
+
theme.replace("-", "_")
|
|
20
|
+
.replace(" ", "_")
|
|
21
|
+
.replace("(", "_")
|
|
22
|
+
.replace(")", "_")
|
|
23
|
+
.replace("+", "_")
|
|
24
|
+
.replace(".", "_")
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if re.match(r"^\d", safe_name):
|
|
28
|
+
safe_name = f"_{safe_name}"
|
|
29
|
+
|
|
30
|
+
theme_enum_entries[safe_name] = theme
|
|
31
|
+
|
|
32
|
+
with open("theme_enum.py", "w") as f:
|
|
33
|
+
f.write("from enum import Enum\n\n")
|
|
34
|
+
f.write("class OutputOptionsTheme(Enum):\n")
|
|
35
|
+
for safe_name, original_name in theme_enum_entries.items():
|
|
36
|
+
f.write(f' {safe_name} = "{original_name}"\n')
|
|
37
|
+
|
|
38
|
+
print("Generated theme_enum.py ✅")
|
|
@@ -371,7 +371,7 @@ def save_theme(theme: dict, filename: pathlib.Path) -> None:
|
|
|
371
371
|
# --- Main Interactive Loop --- #
|
|
372
372
|
|
|
373
373
|
|
|
374
|
-
def
|
|
374
|
+
def theme_builder():
|
|
375
375
|
console = Console(force_terminal=True, color_system="truecolor")
|
|
376
376
|
themes_dir = pathlib.Path(__file__).parent.parent.parent.parent / "themes"
|
|
377
377
|
theme_files = load_theme_files(themes_dir)
|
|
@@ -458,7 +458,7 @@ def main():
|
|
|
458
458
|
)
|
|
459
459
|
if sel2.lower() == "r":
|
|
460
460
|
console.print("Regenerating samples...")
|
|
461
|
-
|
|
461
|
+
theme_builder() # restart the builder
|
|
462
462
|
return
|
|
463
463
|
try:
|
|
464
464
|
sel2 = int(sel2)
|
|
@@ -474,7 +474,3 @@ def main():
|
|
|
474
474
|
save_path = themes_dir / filename
|
|
475
475
|
save_theme(chosen_sample_theme, save_path)
|
|
476
476
|
console.print(f"\n[green]Theme saved as {save_path}.[/green]")
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
if __name__ == "__main__":
|
|
480
|
-
main()
|
|
@@ -5,16 +5,19 @@ import random
|
|
|
5
5
|
import re
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
from devtools import pprint
|
|
9
8
|
from temporalio import workflow
|
|
10
9
|
|
|
11
|
-
from flock.core.logging.formatters.
|
|
10
|
+
from flock.core.logging.formatters.themes import OutputTheme
|
|
12
11
|
|
|
13
12
|
with workflow.unsafe.imports_passed_through():
|
|
13
|
+
from pygments.style import Style
|
|
14
|
+
from pygments.token import Token
|
|
14
15
|
from rich import box
|
|
15
16
|
from rich.console import Console, Group
|
|
16
17
|
from rich.panel import Panel
|
|
18
|
+
from rich.syntax import PygmentsSyntaxTheme, Syntax
|
|
17
19
|
from rich.table import Table
|
|
20
|
+
from rich.theme import Theme
|
|
18
21
|
|
|
19
22
|
import toml # install with: pip install toml
|
|
20
23
|
|
|
@@ -335,18 +338,101 @@ def create_rich_renderable(
|
|
|
335
338
|
return s
|
|
336
339
|
|
|
337
340
|
|
|
338
|
-
|
|
341
|
+
def load_syntax_theme_from_file(filepath: str) -> dict:
|
|
342
|
+
"""Load a syntax highlighting theme from a TOML file and map it to Rich styles."""
|
|
343
|
+
with open(filepath) as f:
|
|
344
|
+
theme = toml.load(f)
|
|
345
|
+
|
|
346
|
+
if "colors" not in theme:
|
|
347
|
+
raise ValueError(
|
|
348
|
+
f"Theme file {filepath} does not contain a 'colors' section."
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# Map theme colors to syntax categories
|
|
352
|
+
syntax_theme = {
|
|
353
|
+
"background": theme["colors"]["primary"].get("background", "#161719"),
|
|
354
|
+
"text": theme["colors"]["primary"].get("foreground", "#c5c8c6"),
|
|
355
|
+
"comment": theme["colors"]["normal"].get("black", "#666666"),
|
|
356
|
+
"keyword": theme["colors"]["bright"].get("magenta", "#ff79c6"),
|
|
357
|
+
"builtin": theme["colors"]["bright"].get("cyan", "#8be9fd"),
|
|
358
|
+
"string": theme["colors"]["bright"].get("green", "#50fa7b"),
|
|
359
|
+
"name": theme["colors"]["bright"].get("blue", "#6272a4"),
|
|
360
|
+
"number": theme["colors"]["bright"].get("yellow", "#f1fa8c"),
|
|
361
|
+
"operator": theme["colors"]["bright"].get("red", "#ff5555"),
|
|
362
|
+
"punctuation": theme["colors"]["normal"].get("white", "#bbbbbb"),
|
|
363
|
+
"error": theme["colors"]["bright"].get("red", "#ff5555"),
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return syntax_theme
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def create_rich_syntax_theme(syntax_theme: dict) -> Theme:
|
|
370
|
+
"""Convert a syntax theme dict to a Rich-compatible Theme."""
|
|
371
|
+
return Theme(
|
|
372
|
+
{
|
|
373
|
+
"background": f"on {syntax_theme['background']}",
|
|
374
|
+
"text": syntax_theme["text"],
|
|
375
|
+
"keyword": f"bold {syntax_theme['keyword']}",
|
|
376
|
+
"builtin": f"bold {syntax_theme['builtin']}",
|
|
377
|
+
"string": syntax_theme["string"],
|
|
378
|
+
"name": syntax_theme["name"],
|
|
379
|
+
"number": syntax_theme["number"],
|
|
380
|
+
"operator": syntax_theme["operator"],
|
|
381
|
+
"punctuation": syntax_theme["punctuation"],
|
|
382
|
+
"error": f"bold {syntax_theme['error']}",
|
|
383
|
+
}
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def create_pygments_syntax_theme(syntax_theme: dict) -> PygmentsSyntaxTheme:
|
|
388
|
+
"""Convert a syntax theme dict to a Pygments-compatible Rich syntax theme."""
|
|
389
|
+
|
|
390
|
+
class CustomSyntaxStyle(Style):
|
|
391
|
+
"""Dynamically generated Pygments style based on the loaded theme."""
|
|
392
|
+
|
|
393
|
+
background_color = syntax_theme["background"]
|
|
394
|
+
styles = {
|
|
395
|
+
Token.Text: syntax_theme["text"],
|
|
396
|
+
Token.Comment: f"italic {syntax_theme['comment']}",
|
|
397
|
+
Token.Keyword: f"bold {syntax_theme['keyword']}",
|
|
398
|
+
Token.Name.Builtin: f"bold {syntax_theme['builtin']}",
|
|
399
|
+
Token.String: syntax_theme["string"],
|
|
400
|
+
Token.Name: syntax_theme["name"],
|
|
401
|
+
Token.Number: syntax_theme["number"],
|
|
402
|
+
Token.Operator: syntax_theme["operator"],
|
|
403
|
+
Token.Punctuation: syntax_theme["punctuation"],
|
|
404
|
+
Token.Error: f"bold {syntax_theme['error']}",
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return PygmentsSyntaxTheme(CustomSyntaxStyle)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
class ThemedAgentResultFormatter:
|
|
339
411
|
"""Formats agent results in a Rich table with nested subtables and theme support."""
|
|
340
412
|
|
|
341
|
-
def __init__(
|
|
413
|
+
def __init__(
|
|
414
|
+
self,
|
|
415
|
+
theme: OutputTheme = OutputTheme.afterglow,
|
|
416
|
+
max_length: int = -1,
|
|
417
|
+
render_table: bool = True,
|
|
418
|
+
wait_for_input: bool = False,
|
|
419
|
+
):
|
|
342
420
|
"""Initialize the formatter with a theme and optional max length."""
|
|
343
421
|
self.theme = theme
|
|
344
422
|
self.styles = None
|
|
345
423
|
self.max_length = max_length
|
|
424
|
+
self.render_table = render_table
|
|
425
|
+
self.wait_for_input = wait_for_input
|
|
346
426
|
|
|
347
427
|
def format_result(
|
|
348
|
-
self,
|
|
428
|
+
self,
|
|
429
|
+
result: dict[str, Any],
|
|
430
|
+
agent_name: str,
|
|
431
|
+
theme,
|
|
432
|
+
styles,
|
|
349
433
|
) -> Panel:
|
|
434
|
+
from devtools import pformat
|
|
435
|
+
|
|
350
436
|
"""Format an agent's result as a Rich Panel containing a table."""
|
|
351
437
|
box_style = (
|
|
352
438
|
getattr(box, styles["table_box"])
|
|
@@ -394,14 +480,32 @@ class ThemedAgentResultFormatter(BaseFormatter):
|
|
|
394
480
|
)
|
|
395
481
|
table.add_row(key, rich_renderable)
|
|
396
482
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
483
|
+
s = pformat(result, highlight=False)
|
|
484
|
+
|
|
485
|
+
if self.render_table:
|
|
486
|
+
return Panel(
|
|
487
|
+
table,
|
|
488
|
+
title="🐤🐧🐓🦆",
|
|
489
|
+
title_align=styles["panel_title_align"],
|
|
490
|
+
border_style=styles["panel_border_style"],
|
|
491
|
+
padding=styles["panel_padding"],
|
|
492
|
+
style=styles["panel_style"],
|
|
493
|
+
)
|
|
494
|
+
else:
|
|
495
|
+
syntax = Syntax(
|
|
496
|
+
s, # The formatted string
|
|
497
|
+
"python", # Highlight as Python (change this for other formats)
|
|
498
|
+
theme=self.syntax_style, # Choose a Rich theme (matches your color setup)
|
|
499
|
+
line_numbers=False,
|
|
500
|
+
)
|
|
501
|
+
return Panel(
|
|
502
|
+
syntax,
|
|
503
|
+
title=agent_name,
|
|
504
|
+
title_align=styles["panel_title_align"],
|
|
505
|
+
border_style=styles["panel_border_style"],
|
|
506
|
+
padding=styles["panel_padding"],
|
|
507
|
+
style=styles["panel_style"],
|
|
508
|
+
)
|
|
405
509
|
|
|
406
510
|
def display_result(self, result: dict[str, Any], agent_name: str) -> None:
|
|
407
511
|
"""Print an agent's result using Rich formatting."""
|
|
@@ -410,7 +514,11 @@ class ThemedAgentResultFormatter(BaseFormatter):
|
|
|
410
514
|
pathlib.Path(__file__).parent.parent.parent.parent / "themes"
|
|
411
515
|
)
|
|
412
516
|
all_themes = list(themes_dir.glob("*.toml"))
|
|
413
|
-
theme =
|
|
517
|
+
theme = (
|
|
518
|
+
theme.value + ".toml"
|
|
519
|
+
if not theme.value.endswith(".toml")
|
|
520
|
+
else theme.value
|
|
521
|
+
)
|
|
414
522
|
theme = (
|
|
415
523
|
pathlib.Path(__file__).parent.parent.parent.parent
|
|
416
524
|
/ "themes"
|
|
@@ -426,6 +534,9 @@ class ThemedAgentResultFormatter(BaseFormatter):
|
|
|
426
534
|
|
|
427
535
|
styles = get_default_styles(theme_dict)
|
|
428
536
|
self.styles = styles
|
|
537
|
+
self.syntax_style = create_pygments_syntax_theme(
|
|
538
|
+
load_syntax_theme_from_file(theme)
|
|
539
|
+
)
|
|
429
540
|
|
|
430
541
|
console = Console()
|
|
431
542
|
panel = self.format_result(
|
|
@@ -435,8 +546,5 @@ class ThemedAgentResultFormatter(BaseFormatter):
|
|
|
435
546
|
styles=styles,
|
|
436
547
|
)
|
|
437
548
|
console.print(panel)
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
def display_data(data: dict[str, Any]) -> None:
|
|
441
|
-
"""Print agent data using Rich formatting."""
|
|
442
|
-
pprint(data)
|
|
549
|
+
if self.wait_for_input:
|
|
550
|
+
console.input(prompt="Press Enter to continue...")
|