flock-core 0.3.21__py3-none-any.whl → 0.3.23__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.

@@ -0,0 +1,214 @@
1
+ """Output formatting and display functionality for agents."""
2
+
3
+ import json
4
+ import os
5
+ from datetime import datetime
6
+ from typing import Any
7
+
8
+ from pydantic import Field
9
+
10
+ from flock.core import FlockAgent
11
+ from flock.core.context.context import FlockContext
12
+ from flock.core.flock_module import FlockModule, FlockModuleConfig
13
+ from flock.core.logging.formatters.themed_formatter import (
14
+ ThemedAgentResultFormatter,
15
+ )
16
+ from flock.core.logging.formatters.themes import OutputTheme
17
+ from flock.core.logging.logging import get_logger
18
+ from flock.core.serialization.json_encoder import FlockJSONEncoder
19
+
20
+ logger = get_logger("module.output")
21
+
22
+
23
+ class OutputModuleConfig(FlockModuleConfig):
24
+ """Configuration for output formatting and display."""
25
+
26
+ theme: OutputTheme = Field(
27
+ default=OutputTheme.afterglow, description="Theme for output formatting"
28
+ )
29
+ render_table: bool = Field(
30
+ default=False, description="Whether to render output as a table"
31
+ )
32
+ max_length: int = Field(
33
+ default=1000, description="Maximum length for displayed output"
34
+ )
35
+ wait_for_input: bool = Field(
36
+ default=False,
37
+ description="Whether to wait for user input after display",
38
+ )
39
+ write_to_file: bool = Field(
40
+ default=False, description="Whether to save output to file"
41
+ )
42
+ output_dir: str = Field(
43
+ default="output/", description="Directory for saving output files"
44
+ )
45
+ truncate_long_values: bool = Field(
46
+ default=True, description="Whether to truncate long values in display"
47
+ )
48
+ show_metadata: bool = Field(
49
+ default=True, description="Whether to show metadata like timestamps"
50
+ )
51
+ format_code_blocks: bool = Field(
52
+ default=True,
53
+ description="Whether to apply syntax highlighting to code blocks",
54
+ )
55
+ custom_formatters: dict[str, str] = Field(
56
+ default_factory=dict,
57
+ description="Custom formatters for specific output types",
58
+ )
59
+ no_output: bool = Field(
60
+ default=False,
61
+ description="Whether to suppress output",
62
+ )
63
+ print_context: bool = Field(
64
+ default=False,
65
+ description="Whether to print the context",
66
+ )
67
+
68
+
69
+ class OutputModule(FlockModule):
70
+ """Module that handles output formatting and display."""
71
+
72
+ name: str = "output"
73
+ config: OutputModuleConfig = Field(
74
+ default_factory=OutputModuleConfig, description="Output configuration"
75
+ )
76
+
77
+ def __init__(self, name: str, config: OutputModuleConfig):
78
+ super().__init__(name=name, config=config)
79
+ if self.config.write_to_file:
80
+ os.makedirs(self.config.output_dir, exist_ok=True)
81
+ self._formatter = ThemedAgentResultFormatter(
82
+ theme=self.config.theme,
83
+ max_length=self.config.max_length,
84
+ render_table=self.config.render_table,
85
+ wait_for_input=self.config.wait_for_input,
86
+ )
87
+
88
+ def _format_value(self, value: Any, key: str) -> str:
89
+ """Format a single value based on its type and configuration."""
90
+ # Check for custom formatter
91
+ if key in self.config.custom_formatters:
92
+ formatter_name = self.config.custom_formatters[key]
93
+ if hasattr(self, f"_format_{formatter_name}"):
94
+ return getattr(self, f"_format_{formatter_name}")(value)
95
+
96
+ # Default formatting based on type
97
+ if isinstance(value, dict):
98
+ return self._format_dict(value)
99
+ elif isinstance(value, list):
100
+ return self._format_list(value)
101
+ elif isinstance(value, str) and self.config.format_code_blocks:
102
+ return self._format_potential_code(value)
103
+ else:
104
+ return str(value)
105
+
106
+ def _format_dict(self, d: dict[str, Any], indent: int = 0) -> str:
107
+ """Format a dictionary with proper indentation."""
108
+ lines = []
109
+ for k, v in d.items():
110
+ formatted_value = self._format_value(v, k)
111
+ if (
112
+ self.config.truncate_long_values
113
+ and len(formatted_value) > self.config.max_length
114
+ ):
115
+ formatted_value = (
116
+ formatted_value[: self.config.max_length] + "..."
117
+ )
118
+ lines.append(f"{' ' * indent}{k}: {formatted_value}")
119
+ return "\n".join(lines)
120
+
121
+ def _format_list(self, lst: list[Any]) -> str:
122
+ """Format a list with proper indentation."""
123
+ return "\n".join(f"- {self._format_value(item, '')}" for item in lst)
124
+
125
+ def _format_potential_code(self, text: str) -> str:
126
+ """Format text that might contain code blocks."""
127
+ import re
128
+
129
+ def replace_code_block(match):
130
+ code = match.group(2)
131
+ lang = match.group(1) if match.group(1) else ""
132
+ # Here you could add syntax highlighting
133
+ return f"```{lang}\n{code}\n```"
134
+
135
+ # Replace code blocks with formatted versions
136
+ text = re.sub(
137
+ r"```(\w+)?\n(.*?)\n```", replace_code_block, text, flags=re.DOTALL
138
+ )
139
+ return text
140
+
141
+ def _save_output(self, agent_name: str, result: dict[str, Any]) -> None:
142
+ """Save output to file if configured."""
143
+ if not self.config.write_to_file:
144
+ return
145
+
146
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
147
+ filename = f"{agent_name}_output_{timestamp}.json"
148
+ filepath = os.path.join(self.config.output_dir, filename)
149
+
150
+ output_data = {
151
+ "agent": agent_name,
152
+ "timestamp": timestamp,
153
+ "output": result,
154
+ }
155
+
156
+ if self.config.show_metadata:
157
+ output_data["metadata"] = {
158
+ "formatted_at": datetime.now().isoformat(),
159
+ "theme": self.config.theme.value,
160
+ "max_length": self.config.max_length,
161
+ }
162
+
163
+ try:
164
+ with open(filepath, "w") as f:
165
+ json.dump(output_data, f, indent=2, cls=FlockJSONEncoder)
166
+ except Exception as e:
167
+ logger.warning(f"Failed to save output to file: {e}")
168
+
169
+ async def post_evaluate(
170
+ self,
171
+ agent: FlockAgent,
172
+ inputs: dict[str, Any],
173
+ result: dict[str, Any],
174
+ context: FlockContext | None = None,
175
+ ) -> dict[str, Any]:
176
+ """Format and display the output."""
177
+ logger.debug("Formatting and displaying output")
178
+ if self.config.no_output:
179
+ return result
180
+ if self.config.print_context:
181
+ result["context"] = context
182
+ # Display the result using the formatter
183
+ self._formatter.display_result(result, agent.name)
184
+
185
+ # Save to file if configured
186
+ self._save_output(agent.name, result)
187
+
188
+ return result
189
+
190
+ def update_theme(self, new_theme: OutputTheme) -> None:
191
+ """Update the output theme."""
192
+ self.config.theme = new_theme
193
+ self._formatter = ThemedAgentResultFormatter(
194
+ theme=self.config.theme,
195
+ max_length=self.config.max_length,
196
+ render_table=self.config.render_table,
197
+ wait_for_input=self.config.wait_for_input,
198
+ write_to_file=self.config.write_to_file,
199
+ )
200
+
201
+ def add_custom_formatter(self, key: str, formatter_name: str) -> None:
202
+ """Add a custom formatter for a specific output key."""
203
+ self.config.custom_formatters[key] = formatter_name
204
+
205
+ def get_output_files(self) -> list[str]:
206
+ """Get list of saved output files."""
207
+ if not self.config.write_to_file:
208
+ return []
209
+
210
+ return [
211
+ f
212
+ for f in os.listdir(self.config.output_dir)
213
+ if f.endswith("_output.json")
214
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flock-core
3
- Version: 0.3.21
3
+ Version: 0.3.23
4
4
  Summary: Declarative LLM Orchestration at Scale
5
5
  Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
6
6
  License-File: LICENSE
@@ -28,6 +28,7 @@ Requires-Dist: opentelemetry-instrumentation-logging>=0.51b0
28
28
  Requires-Dist: opentelemetry-sdk>=1.30.0
29
29
  Requires-Dist: pillow>=10.4.0
30
30
  Requires-Dist: prometheus-client>=0.21.1
31
+ Requires-Dist: psutil>=6.1.1
31
32
  Requires-Dist: pydantic>=2.10.5
32
33
  Requires-Dist: python-box>=7.3.2
33
34
  Requires-Dist: python-decouple>=3.8
@@ -60,6 +60,7 @@ flock/modules/callback/callback_module.py,sha256=volGGgHtY19qj1wHR6m5a_hmXSbV3Ca
60
60
  flock/modules/memory/memory_module.py,sha256=dZ30eOFqIlAz0a5IKJMoXgJ-VyPEqApAOX0OQjhGA1I,14733
61
61
  flock/modules/memory/memory_parser.py,sha256=FLH7GL8XThvHiCMfX3eQH7Sz-f62fzhAUmO6_gaDI7U,4372
62
62
  flock/modules/memory/memory_storage.py,sha256=CNcLDMmvv0x7Z3YMKr6VveS_VCa7rKPw8l2d-XgqokA,27246
63
+ flock/modules/output/output_module.py,sha256=kfHlnhdECC2k7uF_0VZ9_152zHI0qHJ2ZqGwYSsnoro,7621
63
64
  flock/modules/performance/metrics_module.py,sha256=UD9OjY4-zAvauMD7YyDYqE1gyIhzpdr3JkBT8j9knxY,16790
64
65
  flock/modules/zep/zep_module.py,sha256=x7JG6O6xnwwum0RETIqKYbA3xzdcvX2aUuns0Cl0c2Q,6014
65
66
  flock/platform/docker_tools.py,sha256=fpA7-6rJBjPOUBLdQP4ny2QPgJ_042nmqRn5GtKnoYw,1445
@@ -413,8 +414,8 @@ flock/workflow/activities.py,sha256=yah-lHjMW6_Ww1gt7hMXBis1cJRlcbHx0uLsMB9oNZ0,
413
414
  flock/workflow/agent_activities.py,sha256=NhBZscflEf2IMfSRa_pBM_TRP7uVEF_O0ROvWZ33eDc,963
414
415
  flock/workflow/temporal_setup.py,sha256=VWBgmBgfTBjwM5ruS_dVpA5AVxx6EZ7oFPGw4j3m0l0,1091
415
416
  flock/workflow/workflow.py,sha256=I9MryXW_bqYVTHx-nl2epbTqeRy27CAWHHA7ZZA0nAk,1696
416
- flock_core-0.3.21.dist-info/METADATA,sha256=IUx4L0DUqkIx1ZWXBoztYmNDzD85S_zy8PdnPNGXiDU,20620
417
- flock_core-0.3.21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
418
- flock_core-0.3.21.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
419
- flock_core-0.3.21.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
420
- flock_core-0.3.21.dist-info/RECORD,,
417
+ flock_core-0.3.23.dist-info/METADATA,sha256=qwn0OaG4E4j-5vjAPcqSv6jqpxtL8e5NcuhyHgKHkCY,20649
418
+ flock_core-0.3.23.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
419
+ flock_core-0.3.23.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
420
+ flock_core-0.3.23.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
421
+ flock_core-0.3.23.dist-info/RECORD,,