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

@@ -26,6 +26,8 @@ class DeclarativeEvaluatorConfig(FlockEvaluatorConfig):
26
26
  use_cache: bool = True
27
27
  temperature: float = 0.0
28
28
  max_tokens: int = 4096
29
+ max_retries: int = 3
30
+ max_tool_calls: int = 10
29
31
  stream: bool = Field(
30
32
  default=False,
31
33
  description="Enable streaming output from the underlying DSPy program.",
@@ -51,110 +53,132 @@ class DeclarativeEvaluator(
51
53
  _cost: float = PrivateAttr(default=0.0)
52
54
  _lm_history: list = PrivateAttr(default_factory=list)
53
55
 
56
+ # def __init__(self, name: str, config: DeclarativeEvaluatorConfig) -> None:
57
+ # super().__init__(name=name, config=config)
58
+ # self._configure_language_model(
59
+ # model=config.model,
60
+ # use_cache=config.use_cache,
61
+ # temperature=config.temperature,
62
+ # max_tokens=config.max_tokens,
63
+ # )
64
+
54
65
  async def evaluate(
55
- self, agent: FlockAgent, inputs: dict[str, Any], tools: list[Any], mcp_tools: list[Any] | None = None
66
+ self,
67
+ agent: FlockAgent,
68
+ inputs: dict[str, Any],
69
+ tools: list[Any],
70
+ mcp_tools: list[Any] | None = None,
56
71
  ) -> dict[str, Any]:
57
72
  """Evaluate using DSPy, with optional asynchronous streaming."""
58
73
  # --- Setup Signature and LM ---
59
- try:
60
- from rich.console import Console
61
-
62
- console = Console()
63
- _dspy_signature = self.create_dspy_signature_class(
64
- agent.name,
65
- agent.description,
66
- f"{agent.input} -> {agent.output}",
67
- )
68
- # --- Get output field names ---
69
- # dspy.Signature holds fields in .output_fields attribute
70
- output_field_names = list(_dspy_signature.output_fields.keys())
71
- if not output_field_names:
72
- logger.warning(
73
- f"DSPy signature for agent '{agent.name}' has no defined output fields. Streaming might not produce text."
74
- )
75
- # -----------------------------
76
74
 
77
- self._configure_language_model(
75
+ with dspy.context(
76
+ lm=dspy.LM(
78
77
  model=self.config.model or agent.model,
79
- use_cache=self.config.use_cache,
78
+ cache=self.config.use_cache,
80
79
  temperature=self.config.temperature,
81
80
  max_tokens=self.config.max_tokens,
81
+ num_retries=self.config.max_retries,
82
82
  )
83
- agent_task = self._select_task(
84
- _dspy_signature,
85
- override_evaluator_type=self.config.override_evaluator_type,
86
- tools=tools,
87
- mcp_tools=mcp_tools,
88
- kwargs=self.config.kwargs,
89
- )
90
- except Exception as setup_error:
91
- logger.error(
92
- f"Error setting up DSPy task for agent '{agent.name}': {setup_error}",
93
- exc_info=True,
94
- )
95
- raise RuntimeError(
96
- f"DSPy task setup failed: {setup_error}"
97
- ) from setup_error
98
-
99
- # --- Conditional Evaluation (Stream vs No Stream) ---
100
- if self.config.stream:
101
- logger.info(
102
- f"Evaluating agent '{agent.name}' with async streaming."
103
- )
104
- if not callable(agent_task):
105
- logger.error("agent_task is not callable, cannot stream.")
106
- raise TypeError(
107
- "DSPy task could not be created or is not callable."
108
- )
83
+ ):
84
+ try:
85
+ from rich.console import Console
109
86
 
110
- streaming_task = dspy.streamify(agent_task, is_async_program=True)
111
- stream_generator: Generator = streaming_task(**inputs)
112
- delta_content = ""
113
-
114
- console.print("\n")
115
- async for chunk in stream_generator:
116
- if (
117
- hasattr(chunk, "choices")
118
- and chunk.choices
119
- and hasattr(chunk.choices[0], "delta")
120
- and chunk.choices[0].delta
121
- and hasattr(chunk.choices[0].delta, "content")
122
- ):
123
- delta_content = chunk.choices[0].delta.content
124
-
125
- if delta_content:
126
- console.print(delta_content, end="")
127
-
128
- result_dict, cost, lm_history = self._process_result(
129
- chunk, inputs
87
+ console = Console()
88
+ _dspy_signature = self.create_dspy_signature_class(
89
+ agent.name,
90
+ agent.description,
91
+ f"{agent.input} -> {agent.output}",
130
92
  )
131
- self._cost = cost
132
- self._lm_history = lm_history
133
-
134
- console.print("\n")
135
- return self.filter_thought_process(
136
- result_dict, self.config.include_thought_process
137
- )
138
-
139
- else: # Non-streaming path
140
- logger.info(f"Evaluating agent '{agent.name}' without streaming.")
141
- try:
142
- # Ensure the call is awaited if the underlying task is async
143
- result_obj = await agent_task.acall(**inputs)
144
- result_dict, cost, lm_history = self._process_result(
145
- result_obj, inputs
93
+ # --- Get output field names ---
94
+ # dspy.Signature holds fields in .output_fields attribute
95
+ output_field_names = list(_dspy_signature.output_fields.keys())
96
+ if not output_field_names:
97
+ logger.warning(
98
+ f"DSPy signature for agent '{agent.name}' has no defined output fields. Streaming might not produce text."
99
+ )
100
+ # -----------------------------
101
+
102
+ agent_task = self._select_task(
103
+ _dspy_signature,
104
+ override_evaluator_type=self.config.override_evaluator_type,
105
+ tools=tools,
106
+ max_tool_calls=self.config.max_tool_calls,
107
+ mcp_tools=mcp_tools,
108
+ kwargs=self.config.kwargs,
109
+ )
110
+ except Exception as setup_error:
111
+ logger.error(
112
+ f"Error setting up DSPy task for agent '{agent.name}': {setup_error}",
113
+ exc_info=True,
146
114
  )
147
- self._cost = cost
148
- self._lm_history = lm_history
115
+ raise RuntimeError(
116
+ f"DSPy task setup failed: {setup_error}"
117
+ ) from setup_error
118
+
119
+ # --- Conditional Evaluation (Stream vs No Stream) ---
120
+ if self.config.stream:
121
+ logger.info(
122
+ f"Evaluating agent '{agent.name}' with async streaming."
123
+ )
124
+ if not callable(agent_task):
125
+ logger.error("agent_task is not callable, cannot stream.")
126
+ raise TypeError(
127
+ "DSPy task could not be created or is not callable."
128
+ )
129
+
130
+ streaming_task = dspy.streamify(
131
+ agent_task, is_async_program=True
132
+ )
133
+ stream_generator: Generator = streaming_task(**inputs)
134
+ delta_content = ""
135
+
136
+ console.print("\n")
137
+ async for chunk in stream_generator:
138
+ if (
139
+ hasattr(chunk, "choices")
140
+ and chunk.choices
141
+ and hasattr(chunk.choices[0], "delta")
142
+ and chunk.choices[0].delta
143
+ and hasattr(chunk.choices[0].delta, "content")
144
+ ):
145
+ delta_content = chunk.choices[0].delta.content
146
+
147
+ if delta_content:
148
+ console.print(delta_content, end="")
149
+
150
+ result_dict, cost, lm_history = self._process_result(
151
+ chunk, inputs
152
+ )
153
+ self._cost = cost
154
+ self._lm_history = lm_history
155
+
156
+ console.print("\n")
149
157
  return self.filter_thought_process(
150
158
  result_dict, self.config.include_thought_process
151
159
  )
152
- except Exception as e:
153
- logger.error(
154
- f"Error during non-streaming evaluation for agent '{agent.name}': {e}",
155
- exc_info=True,
160
+
161
+ else: # Non-streaming path
162
+ logger.info(
163
+ f"Evaluating agent '{agent.name}' without streaming."
156
164
  )
157
- raise RuntimeError(f"Evaluation failed: {e}") from e
165
+ try:
166
+ # Ensure the call is awaited if the underlying task is async
167
+ result_obj = await agent_task.acall(**inputs)
168
+ result_dict, cost, lm_history = self._process_result(
169
+ result_obj, inputs
170
+ )
171
+ self._cost = cost
172
+ self._lm_history = lm_history
173
+ return self.filter_thought_process(
174
+ result_dict, self.config.include_thought_process
175
+ )
176
+ except Exception as e:
177
+ logger.error(
178
+ f"Error during non-streaming evaluation for agent '{agent.name}': {e}",
179
+ exc_info=True,
180
+ )
181
+ raise RuntimeError(f"Evaluation failed: {e}") from e
158
182
 
159
183
  def filter_thought_process(
160
184
  self, result_dict: dict[str, Any], include_thought_process: bool
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flock-core
3
- Version: 0.4.506
3
+ Version: 0.4.508
4
4
  Summary: Declarative LLM Orchestration at Scale
5
5
  Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
6
6
  License-File: LICENSE
@@ -9,20 +9,15 @@ Classifier: Operating System :: OS Independent
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Requires-Python: >=3.10
11
11
  Requires-Dist: aiosqlite>=0.21.0
12
- Requires-Dist: chromadb>=0.6.3
13
12
  Requires-Dist: cloudpickle>=3.1.1
14
- Requires-Dist: datasets>=3.2.0
15
13
  Requires-Dist: devtools>=0.12.2
16
14
  Requires-Dist: dspy==2.6.23
17
15
  Requires-Dist: fastapi>=0.115.8
18
16
  Requires-Dist: httpx>=0.28.1
19
- Requires-Dist: inspect-ai>=0.3.88
20
17
  Requires-Dist: litellm==1.69.3
21
18
  Requires-Dist: loguru>=0.7.3
22
19
  Requires-Dist: markdown2>=2.5.3
23
- Requires-Dist: matplotlib>=3.10.0
24
20
  Requires-Dist: mcp>=1.7.1
25
- Requires-Dist: mem0ai[graph]>=0.1.101
26
21
  Requires-Dist: msgpack>=1.1.0
27
22
  Requires-Dist: openai==1.75.0
28
23
  Requires-Dist: opentelemetry-api>=1.30.0
@@ -31,6 +26,7 @@ Requires-Dist: opentelemetry-exporter-jaeger>=1.21.0
31
26
  Requires-Dist: opentelemetry-exporter-otlp>=1.30.0
32
27
  Requires-Dist: opentelemetry-instrumentation-logging>=0.51b0
33
28
  Requires-Dist: opentelemetry-sdk>=1.30.0
29
+ Requires-Dist: opik>=1.7.26
34
30
  Requires-Dist: pandas>=2.2.3
35
31
  Requires-Dist: pillow>=10.4.0
36
32
  Requires-Dist: prometheus-client>=0.21.1
@@ -40,12 +36,9 @@ Requires-Dist: pydantic==2.10.5
40
36
  Requires-Dist: python-box>=7.3.2
41
37
  Requires-Dist: python-decouple>=3.8
42
38
  Requires-Dist: python-dotenv>=1.0.1
43
- Requires-Dist: python-fasthtml>=0.12.6
44
39
  Requires-Dist: pyyaml>=6.0
45
40
  Requires-Dist: questionary>=2.1.0
46
41
  Requires-Dist: rich>=13.9.4
47
- Requires-Dist: rouge-score>=0.1.2
48
- Requires-Dist: sentence-transformers>=3.4.1
49
42
  Requires-Dist: temporalio>=1.9.0
50
43
  Requires-Dist: thefuzz>=0.22.1
51
44
  Requires-Dist: tiktoken>=0.8.0
@@ -53,7 +46,23 @@ Requires-Dist: toml>=0.10.2
53
46
  Requires-Dist: tqdm>=4.67.1
54
47
  Requires-Dist: uvicorn>=0.34.0
55
48
  Requires-Dist: wd-di>=0.2.14
56
- Requires-Dist: zep-python>=2.0.2
49
+ Requires-Dist: websockets>=15.0.1
50
+ Provides-Extra: all
51
+ Requires-Dist: azure-identity>=1.23.0; extra == 'all'
52
+ Requires-Dist: azure-search-documents>=11.5.2; extra == 'all'
53
+ Requires-Dist: azure-storage-blob>=12.25.1; extra == 'all'
54
+ Requires-Dist: chromadb>=0.6.3; extra == 'all'
55
+ Requires-Dist: datasets>=3.2.0; extra == 'all'
56
+ Requires-Dist: docling>=2.18.0; extra == 'all'
57
+ Requires-Dist: duckduckgo-search>=7.3.2; extra == 'all'
58
+ Requires-Dist: markdownify>=0.14.1; extra == 'all'
59
+ Requires-Dist: matplotlib>=3.10.0; extra == 'all'
60
+ Requires-Dist: mem0ai[graph]>=0.1.101; extra == 'all'
61
+ Requires-Dist: nltk>=3.9.1; extra == 'all'
62
+ Requires-Dist: rouge-score>=0.1.2; extra == 'all'
63
+ Requires-Dist: sentence-transformers>=3.4.1; extra == 'all'
64
+ Requires-Dist: tavily-python>=0.5.0; extra == 'all'
65
+ Requires-Dist: zep-python>=2.0.2; extra == 'all'
57
66
  Provides-Extra: all-tools
58
67
  Requires-Dist: azure-identity>=1.23.0; extra == 'all-tools'
59
68
  Requires-Dist: azure-search-documents>=11.5.2; extra == 'all-tools'
@@ -72,8 +81,17 @@ Requires-Dist: docling>=2.18.0; extra == 'basic-tools'
72
81
  Requires-Dist: duckduckgo-search>=7.3.2; extra == 'basic-tools'
73
82
  Requires-Dist: markdownify>=0.14.1; extra == 'basic-tools'
74
83
  Requires-Dist: tavily-python>=0.5.0; extra == 'basic-tools'
84
+ Provides-Extra: evaluation
85
+ Requires-Dist: datasets>=3.2.0; extra == 'evaluation'
86
+ Requires-Dist: rouge-score>=0.1.2; extra == 'evaluation'
87
+ Requires-Dist: sentence-transformers>=3.4.1; extra == 'evaluation'
75
88
  Provides-Extra: llm-tools
76
89
  Requires-Dist: nltk>=3.9.1; extra == 'llm-tools'
90
+ Provides-Extra: memory
91
+ Requires-Dist: chromadb>=0.6.3; extra == 'memory'
92
+ Requires-Dist: matplotlib>=3.10.0; extra == 'memory'
93
+ Requires-Dist: mem0ai[graph]>=0.1.101; extra == 'memory'
94
+ Requires-Dist: zep-python>=2.0.2; extra == 'memory'
77
95
  Description-Content-Type: text/markdown
78
96
 
79
97
  <p align="center">
@@ -26,10 +26,10 @@ flock/cli/view_results.py,sha256=dOzK0O1FHSIDERnx48y-2Xke9BkOHS7pcOhs64AyIg0,781
26
26
  flock/cli/yaml_editor.py,sha256=K3N0bh61G1TSDAZDnurqW9e_-hO6CtSQKXQqlDhCjVo,12527
27
27
  flock/cli/assets/release_notes.md,sha256=bqnk50jxM3w5uY44Dc7MkdT8XmRREFxrVBAG9XCOSSU,4896
28
28
  flock/core/__init__.py,sha256=juwyNr3QqKXUS5-E3hlMYRhgqHgQBqgtP12OF3tUCAI,1249
29
- flock/core/flock.py,sha256=M7nk_GncnqPj8pHI4N-3R4hlPRR6BKsLGvoj6sJE89M,37108
30
- flock/core/flock_agent.py,sha256=0AzRr5xLM9cIpOUz6LGMjFeqDMun9wmcj2nc-HFl3Z4,48559
31
- flock/core/flock_evaluator.py,sha256=onbU6r146QVfdrHITF8AMH2U79enAls4QE2gJfpAYVw,1721
32
- flock/core/flock_factory.py,sha256=AXQzecI0fhbJxdDDP7VckqheYX77OJ6ohG0ZU6SxgE4,13873
29
+ flock/core/flock.py,sha256=iR4i0_z0w2ns_iHbP7FqN--7wlsPIWch1H-BVecPs_I,38205
30
+ flock/core/flock_agent.py,sha256=EHI0p3axr8X364wfHMB2js16MQT7H1Awe6SzJQR7bhw,48573
31
+ flock/core/flock_evaluator.py,sha256=TPy6u6XX3cqkY1r9NW1w2lTwCMNW7pxhFYKLefnEbXg,1820
32
+ flock/core/flock_factory.py,sha256=36eOtha-XG67_kK_VadG7UQ8cMgAcd7y1k5yFkT-pR0,14017
33
33
  flock/core/flock_module.py,sha256=ObILimpVaPnaaqYvcBYJJ20lQzfrjgTdADplaNRjHU0,7448
34
34
  flock/core/flock_registry.py,sha256=KzdFfc3QC-Dk42G24hdf6Prp3HvGj9ymXR3TTBe-T-A,27161
35
35
  flock/core/flock_router.py,sha256=1OAXDsdaIIFApEfo6SRfFEDoTuGt3Si7n2MXiySEfis,2644
@@ -42,13 +42,10 @@ flock/core/api/models.py,sha256=seqKuzhbN37nCNO7KrcJjI2mWuwiOKCLFcJcTPvTtag,3422
42
42
  flock/core/api/run_store.py,sha256=bFodJvVyWogzoezVy0cOoWWU3MdEBXf_6_5sBqCRWps,9227
43
43
  flock/core/api/runner.py,sha256=3izg6cVk1RoR1hDIDwMAO1gi3lnLcp8DPv7AnJBYx6A,1443
44
44
  flock/core/api/service.py,sha256=HRHs4xt-bGeSm5hdN92H1vWQtLzqZalhZxIh6iwww8Y,11381
45
- flock/core/api/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
- flock/core/api/ui/routes.py,sha256=nS-wWO94mshE5ozWfOQZ-HOvtes_1qxDVcqpMZtU5JQ,8885
47
- flock/core/api/ui/utils.py,sha256=V7PqYHNK519hFJ8jvvwf7bGpbBXCRz_HQG3BDCCqlNA,4802
48
45
  flock/core/context/context.py,sha256=zdQuB1YWPJmQVv_2_sm1HK7FSnusa3Jl-83PcTuaLUk,7791
49
46
  flock/core/context/context_manager.py,sha256=FANSWa6DEhdhtZ7t_9Gza0v80UdpoDOhHbfVOccmjkA,1181
50
47
  flock/core/context/context_vars.py,sha256=ASPA29hpENWub4mgRoG62FtTVakCHQZfn6IhJQKe3C8,347
51
- flock/core/evaluation/utils.py,sha256=ZJkIMC9YT-HA2SPCZ4_bQ98isW1i6nbltVEYbjze-b0,12827
48
+ flock/core/evaluation/utils.py,sha256=S5M0uTFcClphZsR5EylEzrRNK-1434yImiGYL4pR_5o,15380
52
49
  flock/core/execution/batch_executor.py,sha256=mHwCI-DHqApCv_EVCN0ZOUd-LCQLjREpxKbAUPC0pcY,15266
53
50
  flock/core/execution/evaluation_executor.py,sha256=D9EO0sU-2qWj3vomjmUUi-DOtHNJNFRf30kGDHuzREE,17702
54
51
  flock/core/execution/local_executor.py,sha256=rnIQvaJOs6zZORUcR3vvyS6LPREDJTjaygl_Db0M8ao,952
@@ -79,7 +76,7 @@ flock/core/mcp/types/handlers.py,sha256=mhAoSS6vA3K7YP_mF9Sb2Zn2RvFM8fXxtbwC4zgU
79
76
  flock/core/mcp/types/types.py,sha256=NFVFv0BXy4P79SGe8rKBO4VH41xkpF6Y-yvU3Fmzx6w,4872
80
77
  flock/core/mcp/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
78
  flock/core/mcp/util/helpers.py,sha256=Xlf4iKW_lZxsVMTRoOnV29JsJfAppfmEJrb6sIcoCH4,636
82
- flock/core/mixin/dspy_integration.py,sha256=iJLKyMyebQ-gMKGgw9v1FokLRe4J2vUFm1qJYp2x1-U,17685
79
+ flock/core/mixin/dspy_integration.py,sha256=LQN4cfcG6Myi6kX0-2bKCuK1K_k_lu3SNaTdHHk3lEU,17745
83
80
  flock/core/mixin/prompt_parser.py,sha256=eOqI-FK3y17gVqpc_y5GF-WmK1Jv8mFlkZxTcgweoxI,5121
84
81
  flock/core/serialization/__init__.py,sha256=CML7fPgG6p4c0CDBlJ_uwV1aZZhJKK9uy3IoIHfO87w,431
85
82
  flock/core/serialization/callable_registry.py,sha256=sUZECTZWsM3fJ8FDRQ-FgLNW9hF26nY17AD6fJKADMc,1419
@@ -96,7 +93,7 @@ flock/core/util/loader.py,sha256=j3q2qem5bFMP2SmMuYjb-ISxsNGNZd1baQmpvAnRUUk,224
96
93
  flock/core/util/spliter.py,sha256=rDLnZX158PWkmW8vi2UfMLAMRXcHQFUIydAABd-lDGw,7154
97
94
  flock/evaluators/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
98
95
  flock/evaluators/declarative/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
99
- flock/evaluators/declarative/declarative_evaluator.py,sha256=KOdZcQcezb-3cBBCH-d75tDTdaf4MJxFmsomC92oQRE,6436
96
+ flock/evaluators/declarative/declarative_evaluator.py,sha256=tulTpUOXhF-wMe5a9ULpsCiS1o2Z-DOXOUTqOSzVYqI,7397
100
97
  flock/evaluators/memory/memory_evaluator.py,sha256=ySwz7kcc8suXMJ7gKNSWThW8iOMlE8lUcUzEAHvv8rw,3559
101
98
  flock/evaluators/test/test_case_evaluator.py,sha256=3Emcoty0LOLLBIuPGxSpKphuZC9Fu1DTr1vbGg-hd0Q,1233
102
99
  flock/evaluators/zep/zep_evaluator.py,sha256=6_5vTdU0yJAH8I8w3-MPXiAZx6iUPhAVCsHjrHzkPLM,2058
@@ -557,8 +554,8 @@ flock/workflow/agent_execution_activity.py,sha256=Gy6FtuVAjf0NiUXmC3syS2eJpNQF4R
557
554
  flock/workflow/flock_workflow.py,sha256=iSUF_soFvWar0ffpkzE4irkDZRx0p4HnwmEBi_Ne2sY,9666
558
555
  flock/workflow/temporal_config.py,sha256=3_8O7SDEjMsSMXsWJBfnb6XTp0TFaz39uyzSlMTSF_I,3988
559
556
  flock/workflow/temporal_setup.py,sha256=YIHnSBntzOchHfMSh8hoLeNXrz3B1UbR14YrR6soM7A,1606
560
- flock_core-0.4.506.dist-info/METADATA,sha256=kVh7DDErkkrI4zEXvQV2lR1BNmlvGfSiA9dYGuObKXo,21599
561
- flock_core-0.4.506.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
562
- flock_core-0.4.506.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
563
- flock_core-0.4.506.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
564
- flock_core-0.4.506.dist-info/RECORD,,
557
+ flock_core-0.4.508.dist-info/METADATA,sha256=_THooyyskEuH1CU8OfPv_CcHecZ1lEtSTFjeoOS5Q24,22584
558
+ flock_core-0.4.508.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
559
+ flock_core-0.4.508.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
560
+ flock_core-0.4.508.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
561
+ flock_core-0.4.508.dist-info/RECORD,,
File without changes
@@ -1,271 +0,0 @@
1
- # src/flock/core/api/ui/routes.py
2
- """FastHTML UI routes for the Flock API."""
3
-
4
- from typing import TYPE_CHECKING
5
-
6
- # --- Conditional FastHTML Imports ---
7
- try:
8
- import httpx
9
- from fasthtml.common import *
10
-
11
- # Import Form explicitly with an alias to avoid collisions
12
- from fasthtml.common import Form as FHForm
13
-
14
- FASTHTML_AVAILABLE = True
15
- except ImportError:
16
- FASTHTML_AVAILABLE = False
17
-
18
- # Define necessary dummies if not available
19
- class Request:
20
- pass
21
-
22
- class Titled:
23
- pass
24
-
25
- class Div:
26
- pass
27
-
28
- class H1:
29
- pass
30
-
31
- class P:
32
- pass
33
-
34
- class H2:
35
- pass
36
-
37
- class Pre:
38
- pass
39
-
40
- class Code:
41
- pass
42
-
43
- class Label:
44
- pass
45
-
46
- class Select:
47
- pass
48
-
49
- class Option:
50
- pass
51
-
52
- class FHForm:
53
- pass # Dummy alias if not available
54
-
55
- class Button:
56
- pass
57
-
58
- class Span:
59
- pass
60
-
61
- class Script:
62
- pass
63
-
64
- class Style:
65
- pass
66
-
67
- class Hidden:
68
- pass
69
-
70
- class Textarea:
71
- pass
72
-
73
- class Input:
74
- pass
75
-
76
- def fast_app():
77
- return None, None
78
-
79
- def picolink():
80
- return None
81
- # ------------------------------------
82
-
83
- # Use TYPE_CHECKING to avoid circular import errors for type hints
84
- if TYPE_CHECKING:
85
- from flock.core.api.main import FlockAPI
86
-
87
- # Import logger and utils needed by UI routes
88
- from flock.core.logging.logging import get_logger
89
-
90
- logger = get_logger("api.ui")
91
-
92
-
93
- def create_ui_app(
94
- flock_api_instance: "FlockAPI",
95
- api_host: str,
96
- api_port: int,
97
- server_name: str,
98
- ) -> Any:
99
- """Creates and configures the FastHTML application and its routes."""
100
- if not FASTHTML_AVAILABLE:
101
- raise ImportError("FastHTML is not installed. Cannot create UI.")
102
- logger.debug("Creating FastHTML application instance for UI")
103
-
104
- # Use the passed FlockAPI instance to access necessary data/methods
105
- flock_instance = flock_api_instance.flock
106
- parse_input_spec_func = (
107
- flock_api_instance._parse_input_spec
108
- ) # Get reference to parser
109
-
110
- fh_app, fh_rt = fast_app(
111
- hdrs=(
112
- Script(src="https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js"),
113
- picolink, # Pass directly
114
- Style("""
115
- body { padding: 20px; max-width: 800px; margin: auto; font-family: sans-serif; }
116
- label { display: block; margin-top: 1rem; font-weight: bold;}
117
- input, select, textarea { width: 100%; margin-top: 0.25rem; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }
118
- input[type=checkbox] { width: auto; margin-right: 0.5rem; vertical-align: middle; }
119
- label[for^=input_] { font-weight: normal; display: inline; margin-top: 0;} /* Style for checkbox labels */
120
- button[type=submit] { margin-top: 1.5rem; padding: 0.75rem 1.5rem; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 1rem;}
121
- button[type=submit]:hover { background-color: #0056b3; }
122
- #result-area { margin-top: 2rem; background-color: #f8f9fa; padding: 15px; border: 1px solid #dee2e6; border-radius: 5px; white-space: pre-wrap; word-wrap: break-word; font-family: monospace; }
123
- .htmx-indicator { display: none; margin-left: 10px; font-style: italic; color: #6c757d; }
124
- .htmx-request .htmx-indicator { display: inline; }
125
- .htmx-request.htmx-indicator { display: inline; }
126
- .error-message { color: #721c24; margin-top: 10px; font-weight: bold; background-color: #f8d7da; border: 1px solid #f5c6cb; padding: 10px; border-radius: 5px;}
127
- """),
128
- )
129
- )
130
-
131
- @fh_rt("/get-agent-inputs")
132
- def get_agent_inputs(request: Request):
133
- """Endpoint called by HTMX to get agent input fields."""
134
- agent_name = request.query_params.get("agent_name")
135
- logger.debug(f"UI requesting inputs for agent: {agent_name}")
136
- if not agent_name:
137
- return Div("Please select an agent.", cls="error-message")
138
-
139
- # Access agents via the passed FlockAPI instance
140
- agent_def = flock_instance.agents.get(agent_name)
141
- if not agent_def:
142
- logger.warning(f"Agent '{agent_name}' not found for UI.")
143
- return Div(f"Agent '{agent_name}' not found.", cls="error-message")
144
-
145
- # Use the parsing function from the FlockAPI instance
146
- input_fields = parse_input_spec_func(agent_def.input or "")
147
- logger.debug(f"Parsed input fields for {agent_name}: {input_fields}")
148
-
149
- inputs_html = []
150
- for field in input_fields:
151
- field_id = f"input_{field['name']}"
152
- label_text = f"{field['name']}"
153
- if field["type"] != "bool":
154
- label_text += f" ({field['type']})"
155
- label = Label(label_text, fr=field_id)
156
- input_attrs = dict(
157
- id=field_id,
158
- name=f"inputs.{field['name']}",
159
- type=field["html_type"],
160
- )
161
- if field.get("step"):
162
- input_attrs["step"] = field["step"]
163
- if field.get("desc"):
164
- input_attrs["placeholder"] = field["desc"]
165
- if field.get("rows"):
166
- input_attrs["rows"] = field["rows"]
167
-
168
- if field["html_type"] == "textarea":
169
- input_el = Textarea(**input_attrs)
170
- elif field["html_type"] == "checkbox":
171
- input_el = Div(
172
- Input(**input_attrs, value="true"),
173
- Label(f" Enable?", fr=field_id),
174
- )
175
- else:
176
- input_el = Input(**input_attrs)
177
-
178
- inputs_html.append(
179
- Div(label, input_el, style="margin-bottom: 1rem;")
180
- )
181
-
182
- inputs_html.append(
183
- Hidden(
184
- id="selected_agent_name", name="agent_name", value=agent_name
185
- )
186
- )
187
- return (
188
- Div(*inputs_html)
189
- if inputs_html
190
- else P("This agent requires no input.")
191
- )
192
-
193
- @fh_rt("/")
194
- async def ui_root(request: Request):
195
- """Serves the main UI page."""
196
- logger.info("Serving main UI page /ui/")
197
- agents_list = []
198
- error_msg = None
199
- api_url = f"http://{api_host}:{api_port}/agents"
200
- try:
201
- async with httpx.AsyncClient() as client:
202
- logger.debug(f"UI fetching agents from {api_url}")
203
- response = await client.get(api_url)
204
- response.raise_for_status()
205
- agent_data = response.json()
206
- agents_list = agent_data.get("agents", [])
207
- logger.debug(f"Fetched {len(agents_list)} agents for UI")
208
- except Exception as e:
209
- error_msg = f"UI Error: Could not fetch agent list from API at {api_url}. Details: {e}"
210
- logger.error(error_msg, exc_info=True)
211
-
212
- options = [
213
- Option("-- Select Agent --", value="", selected=True, disabled=True)
214
- ] + [
215
- Option(
216
- f"{agent['name']}: {agent['description']}", value=agent["name"]
217
- )
218
- for agent in agents_list
219
- ]
220
-
221
- # Use FHForm alias here
222
- content = Div(
223
- H2(f"Agent Runner"),
224
- P(
225
- "Select an agent, provide the required inputs, and click 'Run Flock'."
226
- ),
227
- Label("Select Starting Agent:", fr="agent_select"),
228
- Select(
229
- *options,
230
- id="agent_select",
231
- name="agent_name",
232
- hx_get="/ui/get-agent-inputs",
233
- hx_trigger="change",
234
- hx_target="#agent-inputs-container",
235
- hx_indicator="#loading-indicator",
236
- ),
237
- FHForm(
238
- Div(id="agent-inputs-container", style="margin-top: 1rem;"),
239
- Button("Run Flock", type="submit"),
240
- Span(
241
- " Processing...",
242
- id="loading-indicator",
243
- cls="htmx-indicator",
244
- ),
245
- hx_post="/ui/run-agent-form", # Target the dedicated form endpoint
246
- hx_target="#result-area",
247
- hx_swap="innerHTML",
248
- hx_indicator="#loading-indicator",
249
- ),
250
- H2("Result"),
251
- Div(
252
- Pre(
253
- Code(
254
- "Result will appear here...",
255
- id="result-content",
256
- class_="language-json",
257
- )
258
- ),
259
- id="result-area",
260
- style="min-height: 100px;",
261
- ),
262
- )
263
-
264
- if error_msg:
265
- content = Div(
266
- H1("Flock UI - Error"), P(error_msg, cls="error-message")
267
- )
268
-
269
- return Titled(f"{server_name}", content)
270
-
271
- return fh_app