flock-core 0.5.0b26__py3-none-any.whl → 0.5.0b28__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.

@@ -121,6 +121,14 @@ class DeclarativeEvaluationConfig(AgentComponentConfig):
121
121
  default=False,
122
122
  description="Include the reasoning in the output.",
123
123
  )
124
+ status_output_field: str = Field(
125
+ default="_status_output",
126
+ description="The field name for the status output.",
127
+ )
128
+ include_status_output: bool = Field(
129
+ default=False,
130
+ description="Include the status output in the finaloutput.",
131
+ )
124
132
  adapter: Literal["chat", "json", "xml", "two_step"] | None = Field(
125
133
  default=None,
126
134
  description="Optional DSPy adapter to use for formatting/parsing.",
@@ -296,6 +304,7 @@ class DeclarativeEvaluationComponent(
296
304
  from rich.live import Live
297
305
 
298
306
  signature_order = []
307
+ status_field = self.config.status_output_field
299
308
  try:
300
309
  signature_order = list(signature.output_fields.keys())
301
310
  except Exception:
@@ -309,7 +318,10 @@ class DeclarativeEvaluationComponent(
309
318
  if field_name not in display_data:
310
319
  display_data[field_name] = ""
311
320
 
321
+ display_data[status_field] = ""
322
+
312
323
  stream_buffers: defaultdict[str, list[str]] = defaultdict(list)
324
+ stream_buffers[status_field] = []
313
325
 
314
326
  formatter = theme_dict = styles = agent_label = None
315
327
  live_cm = nullcontext()
@@ -359,9 +371,14 @@ class DeclarativeEvaluationComponent(
359
371
  _d = None
360
372
 
361
373
  if isinstance(value, StatusMessage):
362
- message = getattr(value, "message", "")
363
- if message and live is not None:
364
- live.console.log(f"[status] {message}")
374
+ token = getattr(value, "message", "")
375
+ if token:
376
+ stream_buffers[status_field].append(str(token) + "\n")
377
+ display_data[status_field] = "".join(
378
+ stream_buffers[status_field]
379
+ )
380
+ if formatter is not None:
381
+ _refresh_panel()
365
382
  continue
366
383
 
367
384
  if isinstance(value, StreamResponse):
@@ -387,14 +404,37 @@ class DeclarativeEvaluationComponent(
387
404
  continue
388
405
 
389
406
  if isinstance(value, ModelResponseStream):
390
- try:
391
- chunk = value
392
- text = chunk.choices[0].delta.content or ""
393
- if text and live is not None:
394
- live.console.log(text)
395
- except Exception:
396
- pass
407
+ for callback in self.config.stream_callbacks or []:
408
+ try:
409
+ callback(value)
410
+ except Exception as e:
411
+ logger.warning(f"Stream callback error: {e}")
412
+
413
+ chunk = value
414
+ token = chunk.choices[0].delta.content or ""
415
+ signature_field = getattr(
416
+ value, "signature_field_name", None
417
+ )
418
+ if signature_field:
419
+ if signature_field not in display_data:
420
+ display_data[signature_field] = ""
421
+ if token:
422
+ stream_buffers[signature_field].append(str(token))
423
+ display_data[signature_field] = "".join(
424
+ stream_buffers[signature_field]
425
+ )
426
+ if formatter is not None:
427
+ _refresh_panel()
428
+ else:
429
+ if token:
430
+ stream_buffers[status_field].append(str(token))
431
+ display_data[status_field] = "".join(
432
+ stream_buffers[status_field]
433
+ )
434
+ if formatter is not None:
435
+ _refresh_panel()
397
436
  continue
437
+
398
438
 
399
439
  if _d and isinstance(value, _d.Prediction):
400
440
  result_dict, cost, lm_history = self._process_result(
@@ -414,9 +454,14 @@ class DeclarativeEvaluationComponent(
414
454
  ordered_final[field_name] = final_result[
415
455
  field_name
416
456
  ]
457
+
458
+
417
459
  for key, val in final_result.items():
418
460
  if key not in ordered_final:
419
461
  ordered_final[key] = val
462
+
463
+ if self.config.include_status_output:
464
+ ordered_final[self.config.status_output_field] = display_data[self.config.status_output_field]
420
465
  display_data.clear()
421
466
  display_data.update(ordered_final)
422
467
  _refresh_panel()
@@ -533,6 +578,19 @@ class DeclarativeEvaluationComponent(
533
578
  for k, v in result_dict.items()
534
579
  if not (k.startswith("reasoning") or k.startswith("trajectory"))
535
580
  }
581
+
582
+ def filter_status_output(
583
+ self, result_dict: dict[str, Any], include_status_output: bool
584
+ ) -> dict[str, Any]:
585
+ """Filter out status output from the result dictionary."""
586
+ if include_status_output:
587
+ return result_dict
588
+ else:
589
+ return {
590
+ k: v
591
+ for k, v in result_dict.items()
592
+ if not (k.startswith("_status_output"))
593
+ }
536
594
 
537
595
  def filter_reasoning(
538
596
  self, result_dict: dict[str, Any], include_reasoning: bool
@@ -1,11 +1,18 @@
1
1
  # src/flock/components/utility/__init__.py
2
2
  """Utility components for the Flock framework."""
3
3
 
4
+ from .example_utility_component import ExampleUtilityComponent, ExampleUtilityConfig, ExampleRecord
5
+ from .feedback_utility_component import FeedbackUtilityComponent, FeedbackUtilityConfig
4
6
  from .memory_utility_component import MemoryUtilityComponent, MemoryUtilityConfig
5
7
  from .metrics_utility_component import MetricsUtilityComponent, MetricsUtilityConfig
6
8
  from .output_utility_component import OutputUtilityComponent, OutputUtilityConfig
7
9
 
8
10
  __all__ = [
11
+ "ExampleUtilityComponent",
12
+ "ExampleUtilityConfig",
13
+ "ExampleRecord",
14
+ "FeedbackUtilityComponent",
15
+ "FeedbackUtilityConfig",
9
16
  "MemoryUtilityComponent",
10
17
  "MemoryUtilityConfig",
11
18
  "MetricsUtilityComponent",
@@ -0,0 +1,250 @@
1
+ """Example utility component for n-shot learning."""
2
+
3
+ from datetime import datetime, timedelta
4
+ from typing import Any, Literal
5
+
6
+ from pydantic import Field
7
+
8
+ from flock.core.component.agent_component_base import AgentComponentConfig
9
+ from flock.core.component.utility_component import UtilityComponent
10
+ from flock.core.context.context import FlockContext
11
+ from flock.core.logging.logging import get_logger
12
+ from flock.core.registry import flock_component
13
+
14
+ if TYPE_CHECKING:
15
+ from flock.core.flock_agent import FlockAgent
16
+ from flock.webapp.app.services.sharing_store import SharedLinkStoreInterface
17
+
18
+ logger = get_logger("components.utility.example")
19
+
20
+
21
+ class ExampleUtilityConfig(AgentComponentConfig):
22
+ """Configuration for the ExampleUtilityComponent."""
23
+
24
+ # Storage configuration
25
+ storage_type: Literal["sqlite", "azure"] = Field(
26
+ default="sqlite",
27
+ description="Type of storage backend for example data"
28
+ )
29
+
30
+ # SQLite configuration
31
+ sqlite_db_path: str = Field(
32
+ default="./flock_examples.db",
33
+ description="Path to SQLite database file"
34
+ )
35
+
36
+ # Azure Table Storage configuration
37
+ azure_connection_string: str | None = Field(
38
+ default=None,
39
+ description="Azure Table Storage connection string"
40
+ )
41
+ azure_table_name: str = Field(
42
+ default="flockexamples",
43
+ description="Azure Table Storage table name"
44
+ )
45
+
46
+ # Example selection criteria
47
+ max_examples: int = Field(
48
+ default=5,
49
+ description="Maximum number of examples to include"
50
+ )
51
+ example_timeframe_days: int = Field(
52
+ default=30,
53
+ description="Only include examples from the last N days"
54
+ )
55
+
56
+ # Example injection settings
57
+ example_input_key: str = Field(
58
+ default="examples_context",
59
+ description="Input key to use for injected examples"
60
+ )
61
+
62
+ # Example filtering
63
+ example_filter_keywords: list[str] = Field(
64
+ default_factory=list,
65
+ description="Keywords to filter examples (only include examples containing these)"
66
+ )
67
+ example_exclude_keywords: list[str] = Field(
68
+ default_factory=list,
69
+ description="Keywords to exclude examples containing these"
70
+ )
71
+
72
+
73
+ @flock_component(config_class=ExampleUtilityConfig)
74
+ class ExampleUtilityComponent(UtilityComponent):
75
+ """Utility component that injects relevant examples into agent inputs for n-shot learning."""
76
+
77
+ config: ExampleUtilityConfig = Field(
78
+ default_factory=ExampleUtilityConfig,
79
+ description="Example component configuration"
80
+ )
81
+
82
+ def __init__(self, name: str = "examples", config: ExampleUtilityConfig | None = None, **data):
83
+ super().__init__(name=name, config=config or ExampleUtilityConfig(), **data)
84
+ self._store: SharedLinkStoreInterface | None = None
85
+
86
+ async def _get_store(self) -> SharedLinkStoreInterface:
87
+ """Get the appropriate example store based on configuration."""
88
+ if self._store is None:
89
+ if self.config.storage_type == "sqlite":
90
+ from flock.webapp.app.services.sharing_store import SQLiteSharedLinkStore
91
+ self._store = SQLiteSharedLinkStore(self.config.sqlite_db_path)
92
+ elif self.config.storage_type == "azure":
93
+ if not self.config.azure_connection_string:
94
+ raise ValueError("Azure connection string is required for Azure storage")
95
+ from flock.webapp.app.services.sharing_store import AzureTableSharedLinkStore
96
+ self._store = AzureTableSharedLinkStore(
97
+ connection_string=self.config.azure_connection_string,
98
+ table_name=self.config.azure_table_name
99
+ )
100
+ else:
101
+ raise ValueError(f"Unsupported storage type: {self.config.storage_type}")
102
+
103
+ await self._store.initialize()
104
+
105
+ return self._store
106
+
107
+ @staticmethod
108
+ def seed_examples(examples: list["ExampleRecord"]) -> None:
109
+ """Seed examples into the storage system.
110
+
111
+ Args:
112
+ examples: List of ExampleRecord objects to seed
113
+ """
114
+ import asyncio
115
+
116
+ async def _seed_examples():
117
+ # Create a default component for seeding
118
+ component = ExampleUtilityComponent()
119
+ store = await component._get_store()
120
+
121
+ for example in examples:
122
+ await store.save_example(example)
123
+
124
+ logger.info(f"Seeded {len(examples)} examples into storage")
125
+
126
+ # Run the async function
127
+ asyncio.run(_seed_examples())
128
+
129
+ async def _get_relevant_examples(
130
+ self,
131
+ agent_name: str,
132
+ inputs: dict[str, Any]
133
+ ) -> list["ExampleRecord"]:
134
+ """Get relevant examples for the given agent and inputs."""
135
+ store = await self._get_store()
136
+
137
+ # Get all examples for this agent
138
+ all_examples = await store.get_all_examples_for_agent(agent_name)
139
+
140
+ # Filter by timeframe
141
+ cutoff_date = datetime.utcnow() - timedelta(days=self.config.example_timeframe_days)
142
+ filtered_examples = [
143
+ ex for ex in all_examples
144
+ if ex.created_at >= cutoff_date
145
+ ]
146
+
147
+ # Filter by keywords if specified
148
+ if self.config.example_filter_keywords:
149
+ filtered_examples = [
150
+ ex for ex in filtered_examples
151
+ if any(keyword.lower() in ex.content.lower() for keyword in self.config.example_filter_keywords)
152
+ ]
153
+
154
+ # Exclude by keywords if specified
155
+ if self.config.example_exclude_keywords:
156
+ filtered_examples = [
157
+ ex for ex in filtered_examples
158
+ if not any(keyword.lower() in ex.content.lower() for keyword in self.config.example_exclude_keywords)
159
+ ]
160
+
161
+ # Sort by recency and limit
162
+ filtered_examples.sort(key=lambda ex: ex.created_at, reverse=True)
163
+ return filtered_examples[:self.config.max_examples]
164
+
165
+ def _format_examples_for_injection(
166
+ self,
167
+ example_records: list["ExampleRecord"]
168
+ ) -> str:
169
+ """Format example records for injection into agent input."""
170
+ if not example_records:
171
+ return "No relevant examples available."
172
+
173
+ formatted_parts = []
174
+ formatted_parts.append(f"Here are {len(example_records)} examples to guide your response:")
175
+
176
+ for i, ex in enumerate(example_records, 1):
177
+ ex_text = f"\nExample {i} (ID: {ex.example_id}):"
178
+ ex_text += f"\n{ex.content}"
179
+ ex_text += f"\nDate: {ex.created_at.strftime('%Y-%m-%d')}"
180
+ formatted_parts.append(ex_text)
181
+
182
+ return "\n".join(formatted_parts)
183
+
184
+ async def on_pre_evaluate(
185
+ self,
186
+ agent: "FlockAgent",
187
+ inputs: dict[str, Any],
188
+ context: FlockContext | None = None,
189
+ ) -> dict[str, Any]:
190
+ """Inject relevant examples into agent inputs before evaluation."""
191
+ logger.debug(f"Injecting examples for agent '{agent.name}'")
192
+
193
+ try:
194
+ # Get relevant examples for this agent
195
+ example_records = await self._get_relevant_examples(agent.name, inputs)
196
+
197
+ # Format examples for injection
198
+ formatted_examples = self._format_examples_for_injection(example_records)
199
+
200
+ # Create a copy of inputs to avoid modifying the original
201
+ enhanced_inputs = inputs.copy()
202
+
203
+ # Inject examples using the configured key
204
+ enhanced_inputs[self.config.example_input_key] = formatted_examples
205
+
206
+ logger.debug(f"Injected {len(example_records)} examples into '{self.config.example_input_key}'")
207
+
208
+ return enhanced_inputs
209
+
210
+ except Exception as e:
211
+ logger.error(f"Error injecting examples: {e}")
212
+ # Return original inputs if example injection fails
213
+ return inputs
214
+
215
+
216
+ # Example record model
217
+ class ExampleRecord:
218
+ """Record for storing example data."""
219
+
220
+ def __init__(
221
+ self,
222
+ agent_name: str,
223
+ example_id: str,
224
+ content: str,
225
+ created_at: datetime | None = None
226
+ ):
227
+ self.agent_name = agent_name
228
+ self.example_id = example_id
229
+ self.content = content
230
+ self.created_at = created_at or datetime.utcnow()
231
+
232
+ def to_dict(self) -> dict[str, Any]:
233
+ """Convert to dictionary for storage."""
234
+ return {
235
+ "agent_name": self.agent_name,
236
+ "example_id": self.example_id,
237
+ "content": self.content,
238
+ "created_at": self.created_at.isoformat(),
239
+ "context_type": "example"
240
+ }
241
+
242
+ @classmethod
243
+ def from_dict(cls, data: dict[str, Any]) -> "ExampleRecord":
244
+ """Create from dictionary from storage."""
245
+ return cls(
246
+ agent_name=data["agent_name"],
247
+ example_id=data["example_id"],
248
+ content=data["content"],
249
+ created_at=datetime.fromisoformat(data["created_at"])
250
+ )
@@ -0,0 +1,206 @@
1
+ """Feedback utility component for learning from user feedback."""
2
+
3
+ from datetime import datetime, timedelta
4
+ from typing import TYPE_CHECKING, Any, Literal
5
+
6
+ from pydantic import Field
7
+
8
+ from flock.core.component.agent_component_base import AgentComponentConfig
9
+ from flock.core.component.utility_component import UtilityComponent
10
+ from flock.core.context.context import FlockContext
11
+ from flock.core.logging.logging import get_logger
12
+ from flock.core.registry import flock_component
13
+
14
+ if TYPE_CHECKING:
15
+ from flock.core.flock_agent import FlockAgent
16
+ from flock.webapp.app.services.sharing_models import FeedbackRecord
17
+ from flock.webapp.app.services.sharing_store import SharedLinkStoreInterface
18
+
19
+ logger = get_logger("components.utility.feedback")
20
+
21
+
22
+ class FeedbackUtilityConfig(AgentComponentConfig):
23
+ """Configuration for the FeedbackUtilityComponent."""
24
+
25
+ # Storage configuration
26
+ storage_type: Literal["sqlite", "azure"] = Field(
27
+ default="sqlite",
28
+ description="Type of storage backend for feedback data"
29
+ )
30
+
31
+ # SQLite configuration
32
+ sqlite_db_path: str = Field(
33
+ default="./flock_feedback.db",
34
+ description="Path to SQLite database file"
35
+ )
36
+
37
+ # Azure Table Storage configuration
38
+ azure_connection_string: str | None = Field(
39
+ default=None,
40
+ description="Azure Table Storage connection string"
41
+ )
42
+ azure_table_name: str = Field(
43
+ default="flockfeedback",
44
+ description="Azure Table Storage table name"
45
+ )
46
+
47
+ # Feedback selection criteria
48
+ max_feedback_items: int = Field(
49
+ default=5,
50
+ description="Maximum number of feedback items to include"
51
+ )
52
+ feedback_timeframe_days: int = Field(
53
+ default=30,
54
+ description="Only include feedback from the last N days"
55
+ )
56
+
57
+ # Feedback injection settings
58
+ feedback_input_key: str = Field(
59
+ default="feedback_context",
60
+ description="Input key to use for injected feedback"
61
+ )
62
+ include_expected_responses: bool = Field(
63
+ default=True,
64
+ description="Whether to include expected responses from feedback"
65
+ )
66
+ include_actual_responses: bool = Field(
67
+ default=False,
68
+ description="Whether to include actual responses from feedback"
69
+ )
70
+
71
+ # Feedback filtering
72
+ feedback_filter_keywords: list[str] = Field(
73
+ default_factory=list,
74
+ description="Keywords to filter feedback (only include feedback containing these)"
75
+ )
76
+ feedback_exclude_keywords: list[str] = Field(
77
+ default_factory=list,
78
+ description="Keywords to exclude feedback containing these"
79
+ )
80
+
81
+
82
+ @flock_component(config_class=FeedbackUtilityConfig)
83
+ class FeedbackUtilityComponent(UtilityComponent):
84
+ """Utility component that injects relevant feedback into agent inputs."""
85
+
86
+ config: FeedbackUtilityConfig = Field(
87
+ default_factory=FeedbackUtilityConfig,
88
+ description="Feedback component configuration"
89
+ )
90
+
91
+ def __init__(self, name: str = "feedback", config: FeedbackUtilityConfig | None = None, **data):
92
+ super().__init__(name=name, config=config or FeedbackUtilityConfig(), **data)
93
+ self._store: SharedLinkStoreInterface | None = None
94
+
95
+ async def _get_store(self) -> SharedLinkStoreInterface:
96
+ """Get the appropriate feedback store based on configuration."""
97
+ if self._store is None:
98
+ if self.config.storage_type == "sqlite":
99
+ from flock.webapp.app.services.sharing_store import SQLiteSharedLinkStore
100
+ self._store = SQLiteSharedLinkStore(self.config.sqlite_db_path)
101
+ elif self.config.storage_type == "azure":
102
+ if not self.config.azure_connection_string:
103
+ raise ValueError("Azure connection string is required for Azure storage")
104
+ from flock.webapp.app.services.sharing_store import AzureTableSharedLinkStore
105
+ self._store = AzureTableSharedLinkStore(
106
+ connection_string=self.config.azure_connection_string,
107
+ table_name=self.config.azure_table_name
108
+ )
109
+ else:
110
+ raise ValueError(f"Unsupported storage type: {self.config.storage_type}")
111
+
112
+ await self._store.initialize()
113
+
114
+ return self._store
115
+
116
+ async def _get_relevant_feedback(
117
+ self,
118
+ agent_name: str,
119
+ inputs: dict[str, Any]
120
+ ) -> list["FeedbackRecord"]:
121
+ """Get relevant feedback for the given agent and inputs."""
122
+ store = await self._get_store()
123
+
124
+ # Get all feedback for this agent
125
+ all_feedback = await store.get_all_feedback_records_for_agent(agent_name)
126
+
127
+ # Filter by timeframe
128
+ cutoff_date = datetime.utcnow() - timedelta(days=self.config.feedback_timeframe_days)
129
+ filtered_feedback = [
130
+ fb for fb in all_feedback
131
+ if fb.created_at >= cutoff_date
132
+ ]
133
+
134
+ # Filter by keywords if specified
135
+ if self.config.feedback_filter_keywords:
136
+ filtered_feedback = [
137
+ fb for fb in filtered_feedback
138
+ if any(keyword.lower() in fb.reason.lower() for keyword in self.config.feedback_filter_keywords)
139
+ ]
140
+
141
+ # Exclude by keywords if specified
142
+ if self.config.feedback_exclude_keywords:
143
+ filtered_feedback = [
144
+ fb for fb in filtered_feedback
145
+ if not any(keyword.lower() in fb.reason.lower() for keyword in self.config.feedback_exclude_keywords)
146
+ ]
147
+
148
+ # Sort by recency and limit
149
+ filtered_feedback.sort(key=lambda fb: fb.created_at, reverse=True)
150
+ return filtered_feedback[:self.config.max_feedback_items]
151
+
152
+ def _format_feedback_for_injection(
153
+ self,
154
+ feedback_records: list["FeedbackRecord"]
155
+ ) -> str:
156
+ """Format feedback records for injection into agent input."""
157
+ if not feedback_records:
158
+ return "No relevant feedback available."
159
+
160
+ formatted_parts = []
161
+ formatted_parts.append(f"Here are {len(feedback_records)} pieces of relevant feedback from previous interactions:")
162
+
163
+ for i, fb in enumerate(feedback_records, 1):
164
+ fb_text = f"\n{i}. Feedback: {fb.reason}"
165
+
166
+ if self.config.include_expected_responses and fb.expected_response:
167
+ fb_text += f"\n Expected response: {fb.expected_response}"
168
+
169
+ if self.config.include_actual_responses and fb.actual_response:
170
+ fb_text += f"\n Actual response: {fb.actual_response}"
171
+
172
+ fb_text += f"\n Date: {fb.created_at.strftime('%Y-%m-%d')}"
173
+ formatted_parts.append(fb_text)
174
+
175
+ return "\n".join(formatted_parts)
176
+
177
+ async def on_pre_evaluate(
178
+ self,
179
+ agent: "FlockAgent",
180
+ inputs: dict[str, Any],
181
+ context: FlockContext | None = None,
182
+ ) -> dict[str, Any]:
183
+ """Inject relevant feedback into agent inputs before evaluation."""
184
+ logger.debug(f"Injecting feedback for agent '{agent.name}'")
185
+
186
+ try:
187
+ # Get relevant feedback for this agent
188
+ feedback_records = await self._get_relevant_feedback(agent.name, inputs)
189
+
190
+ # Format feedback for injection
191
+ formatted_feedback = self._format_feedback_for_injection(feedback_records)
192
+
193
+ # Create a copy of inputs to avoid modifying the original
194
+ enhanced_inputs = inputs.copy()
195
+
196
+ # Inject feedback using the configured key
197
+ enhanced_inputs[self.config.feedback_input_key] = formatted_feedback
198
+
199
+ logger.debug(f"Injected {len(feedback_records)} feedback items into '{self.config.feedback_input_key}'")
200
+
201
+ return enhanced_inputs
202
+
203
+ except Exception as e:
204
+ logger.error(f"Error injecting feedback: {e}")
205
+ # Return original inputs if feedback injection fails
206
+ return inputs
@@ -10,6 +10,14 @@ from __future__ import annotations
10
10
  from collections.abc import Callable
11
11
  from typing import Any, Literal
12
12
 
13
+ from flock.components.utility.example_utility_component import (
14
+ ExampleUtilityComponent,
15
+ ExampleUtilityConfig,
16
+ )
17
+ from flock.components.utility.feedback_utility_component import (
18
+ FeedbackUtilityComponent,
19
+ FeedbackUtilityConfig,
20
+ )
13
21
  from flock.components.utility.metrics_utility_component import (
14
22
  MetricsUtilityComponent,
15
23
  MetricsUtilityConfig,
@@ -28,6 +36,7 @@ class DefaultAgent(FlockAgent):
28
36
  - DeclarativeEvaluationComponent (LLM evaluation)
29
37
  - OutputUtilityComponent (formatting/printing)
30
38
  - MetricsUtilityComponent (latency tracking)
39
+ - FeedbackUtilityComponent (feedback learning) - optional
31
40
  """
32
41
 
33
42
  def __init__(
@@ -44,13 +53,14 @@ class DefaultAgent(FlockAgent):
44
53
  use_cache: bool = False,
45
54
  temperature: float = 0.7,
46
55
  max_tokens: int | None = None,
47
- max_tool_calls: int = 0,
56
+ max_tool_calls: int = 10,
48
57
  max_retries: int = 2,
49
58
  stream: bool = True,
50
59
  stream_callbacks: list[Callable[..., Any] | Any] | None = None,
51
60
  stream_vertical_overflow: Literal["crop", "ellipsis", "crop_above", "visible"] = "crop_above",
52
61
  include_thought_process: bool = False,
53
62
  include_reasoning: bool = False,
63
+ include_status_output: bool = False,
54
64
  # Output utility parameters
55
65
  enable_rich_tables: bool = True,
56
66
  output_theme: OutputTheme | None = None,
@@ -61,6 +71,12 @@ class DefaultAgent(FlockAgent):
61
71
  wait_for_input: bool = False,
62
72
  # Metrics utility
63
73
  alert_latency_threshold_ms: int = 30_000,
74
+ # Feedback utility
75
+ enable_feedback: bool = False,
76
+ feedback_config: FeedbackUtilityConfig | None = None,
77
+ # Example utility
78
+ enable_examples: bool = False,
79
+ example_config: ExampleUtilityConfig | None = None,
64
80
  # Workflow
65
81
  next_agent: DynamicStr | None = None,
66
82
  temporal_activity_config: TemporalActivityConfig | None = None,
@@ -90,6 +106,7 @@ class DefaultAgent(FlockAgent):
90
106
  stream_vertical_overflow: Rich Live overflow handling ('ellipsis', 'crop', 'crop_above', 'visible')
91
107
  include_thought_process: Include reasoning in output
92
108
  include_reasoning: Include detailed reasoning steps
109
+ include_status_output: Include status output in output
93
110
  enable_rich_tables: Enable rich table formatting for output
94
111
  output_theme: Theme for output formatting
95
112
  no_output: Disable output printing
@@ -97,6 +114,10 @@ class DefaultAgent(FlockAgent):
97
114
  write_to_file: Save outputs to file
98
115
  wait_for_input: Wait for user input after execution
99
116
  alert_latency_threshold_ms: Threshold for latency alerts
117
+ enable_feedback: Whether to enable feedback learning component
118
+ feedback_config: Configuration for feedback component
119
+ enable_examples: Whether to enable example learning component
120
+ example_config: Configuration for example component
100
121
  next_agent: Next agent in workflow chain
101
122
  temporal_activity_config: Configuration for Temporal workflow execution
102
123
  """
@@ -129,6 +150,7 @@ class DefaultAgent(FlockAgent):
129
150
  stream_vertical_overflow=stream_vertical_overflow,
130
151
  include_thought_process=include_thought_process,
131
152
  include_reasoning=include_reasoning,
153
+ include_status_output=include_status_output,
132
154
  )
133
155
  if max_tokens is not None:
134
156
  _eval_kwargs["max_tokens"] = max_tokens
@@ -158,6 +180,23 @@ class DefaultAgent(FlockAgent):
158
180
  name="metrics_tracker", config=metrics_config
159
181
  )
160
182
 
183
+ # Feedback utility component (optional)
184
+ components = [evaluator, output_component, metrics_component]
185
+ if enable_feedback:
186
+ feedback_component = FeedbackUtilityComponent(
187
+ name="feedback",
188
+ config=feedback_config or FeedbackUtilityConfig()
189
+ )
190
+ components.append(feedback_component)
191
+
192
+ # Example utility component (optional)
193
+ if enable_examples:
194
+ example_component = ExampleUtilityComponent(
195
+ name="examples",
196
+ config=example_config or ExampleUtilityConfig()
197
+ )
198
+ components.append(example_component)
199
+
161
200
  super().__init__(
162
201
  name=name,
163
202
  model=model,
@@ -167,7 +206,7 @@ class DefaultAgent(FlockAgent):
167
206
  tools=tools,
168
207
  servers=servers,
169
208
  tool_whitelist=tool_whitelist,
170
- components=[evaluator, output_component, metrics_component],
209
+ components=components,
171
210
  config=FlockAgentConfig(
172
211
  write_to_file=write_to_file,
173
212
  wait_for_input=wait_for_input,
@@ -443,6 +443,30 @@ class FlockFactory:
443
443
  include_reasoning: bool = False,
444
444
  next_agent: DynamicStr | None = None,
445
445
  temporal_activity_config: TemporalActivityConfig | None = None,
446
+ # Feedback parameters
447
+ enable_feedback: bool = False,
448
+ feedback_storage_type: Literal["sqlite", "azure"] = "sqlite",
449
+ feedback_max_items: int = 5,
450
+ feedback_timeframe_days: int = 30,
451
+ feedback_input_key: str = "feedback_context",
452
+ feedback_include_expected_responses: bool = True,
453
+ feedback_include_actual_responses: bool = False,
454
+ feedback_filter_keywords: list[str] | None = None,
455
+ feedback_exclude_keywords: list[str] | None = None,
456
+ feedback_sqlite_db_path: str = "./flock_feedback.db",
457
+ feedback_azure_connection_string: str | None = None,
458
+ feedback_azure_table_name: str = "flockfeedback",
459
+ # Example parameters
460
+ enable_examples: bool = False,
461
+ example_storage_type: Literal["sqlite", "azure"] = "sqlite",
462
+ example_max_examples: int = 5,
463
+ example_timeframe_days: int = 30,
464
+ example_input_key: str = "examples_context",
465
+ example_filter_keywords: list[str] | None = None,
466
+ example_exclude_keywords: list[str] | None = None,
467
+ example_sqlite_db_path: str = "./flock_examples.db",
468
+ example_azure_connection_string: str | None = None,
469
+ example_azure_table_name: str = "flockexamples",
446
470
  ) -> FlockAgent:
447
471
  """Create a default FlockAgent.
448
472
 
@@ -452,6 +476,40 @@ class FlockFactory:
452
476
  """
453
477
  _maybe_warn_factory_deprecation()
454
478
 
479
+ # Configure feedback if enabled
480
+ feedback_config = None
481
+ if enable_feedback:
482
+ from flock.components.utility.feedback_utility_component import FeedbackUtilityConfig
483
+ feedback_config = FeedbackUtilityConfig(
484
+ storage_type=feedback_storage_type,
485
+ max_feedback_items=feedback_max_items,
486
+ feedback_timeframe_days=feedback_timeframe_days,
487
+ feedback_input_key=feedback_input_key,
488
+ include_expected_responses=feedback_include_expected_responses,
489
+ include_actual_responses=feedback_include_actual_responses,
490
+ feedback_filter_keywords=feedback_filter_keywords or [],
491
+ feedback_exclude_keywords=feedback_exclude_keywords or [],
492
+ sqlite_db_path=feedback_sqlite_db_path,
493
+ azure_connection_string=feedback_azure_connection_string,
494
+ azure_table_name=feedback_azure_table_name,
495
+ )
496
+
497
+ # Configure examples if enabled
498
+ example_config = None
499
+ if enable_examples:
500
+ from flock.components.utility.example_utility_component import ExampleUtilityConfig
501
+ example_config = ExampleUtilityConfig(
502
+ storage_type=example_storage_type,
503
+ max_examples=example_max_examples,
504
+ example_timeframe_days=example_timeframe_days,
505
+ example_input_key=example_input_key,
506
+ example_filter_keywords=example_filter_keywords or [],
507
+ example_exclude_keywords=example_exclude_keywords or [],
508
+ sqlite_db_path=example_sqlite_db_path,
509
+ azure_connection_string=example_azure_connection_string,
510
+ azure_table_name=example_azure_table_name,
511
+ )
512
+
455
513
  return DefaultAgent(
456
514
  name=name,
457
515
  description=description,
@@ -477,6 +535,10 @@ class FlockFactory:
477
535
  alert_latency_threshold_ms=alert_latency_threshold_ms,
478
536
  next_agent=next_agent,
479
537
  temporal_activity_config=temporal_activity_config,
538
+ enable_feedback=enable_feedback,
539
+ feedback_config=feedback_config,
540
+ enable_examples=enable_examples,
541
+ example_config=example_config,
480
542
  )
481
543
 
482
544
  @staticmethod
@@ -256,6 +256,14 @@ def create_rich_renderable(
256
256
  if styles is None:
257
257
  styles = get_default_styles(theme)
258
258
 
259
+ # Convert Pydantic BaseModel instances to dicts for rendering
260
+ try:
261
+ from pydantic import BaseModel
262
+ if isinstance(value, BaseModel):
263
+ value = value.model_dump()
264
+ except ImportError:
265
+ pass
266
+
259
267
  # If the value is a dictionary, render it as a table.
260
268
  if isinstance(value, dict):
261
269
  # Convert table_box string into an actual box style.
@@ -5,6 +5,7 @@ import sqlite3
5
5
  from abc import ABC, abstractmethod
6
6
  from pathlib import Path
7
7
  from typing import Any
8
+ from datetime import datetime
8
9
 
9
10
  import aiosqlite
10
11
 
@@ -65,6 +66,22 @@ class SharedLinkStoreInterface(ABC):
65
66
  async def get_all_feedback_records_for_agent(self, agent_name: str) -> list[FeedbackRecord]:
66
67
  """Get all feedback records for a given agent."""
67
68
  pass
69
+
70
+ # Examples
71
+ @abstractmethod
72
+ async def save_example(self, example: Any):
73
+ """Persist an example record."""
74
+ pass
75
+
76
+ @abstractmethod
77
+ async def get_example(self, id: str) -> Any | None:
78
+ """Get a single example record."""
79
+ pass
80
+
81
+ @abstractmethod
82
+ async def get_all_examples_for_agent(self, agent_name: str) -> list[Any]:
83
+ """Get all example records for a given agent."""
84
+ pass
68
85
 
69
86
  class SQLiteSharedLinkStore(SharedLinkStoreInterface):
70
87
  """SQLite implementation for storing and retrieving shared link configurations."""
@@ -99,18 +116,13 @@ class SQLiteSharedLinkStore(SharedLinkStoreInterface):
99
116
  ("chat_history_key", "TEXT"),
100
117
  ("chat_response_key", "TEXT")
101
118
  ]
102
-
103
- for column_name, column_type in new_columns:
119
+ for col_name, col_def in new_columns:
104
120
  try:
105
- await db.execute(f"ALTER TABLE shared_links ADD COLUMN {column_name} {column_type}")
106
- logger.info(f"Added column '{column_name}' to shared_links table.")
107
- except sqlite3.OperationalError as e:
108
- if "duplicate column name" in str(e).lower():
109
- logger.debug(f"Column '{column_name}' already exists in shared_links table.")
110
- else:
111
- raise # Re-raise if it's a different operational error
112
-
113
- # Feedback table
121
+ await db.execute(f"ALTER TABLE shared_links ADD COLUMN {col_name} {col_def}")
122
+ except sqlite3.OperationalError:
123
+ pass # Column already exists
124
+
125
+ # Create feedback table if it doesn't exist
114
126
  await db.execute(
115
127
  """
116
128
  CREATE TABLE IF NOT EXISTS feedback (
@@ -123,16 +135,27 @@ class SQLiteSharedLinkStore(SharedLinkStoreInterface):
123
135
  flock_name TEXT,
124
136
  agent_name TEXT,
125
137
  flock_definition TEXT,
138
+ created_at TEXT NOT NULL
139
+ )
140
+ """
141
+ )
142
+
143
+ # Create examples table if it doesn't exist
144
+ await db.execute(
145
+ """
146
+ CREATE TABLE IF NOT EXISTS examples (
147
+ example_id TEXT PRIMARY KEY,
148
+ agent_name TEXT NOT NULL,
149
+ content TEXT NOT NULL,
126
150
  created_at TEXT NOT NULL,
127
- FOREIGN KEY(share_id) REFERENCES shared_links(share_id)
151
+ context_type TEXT NOT NULL DEFAULT 'example'
128
152
  )
129
153
  """
130
154
  )
131
155
 
132
156
  await db.commit()
133
- logger.info(f"Database initialized and shared_links table schema ensured at {self.db_path}")
134
- except sqlite3.Error as e:
135
- logger.error(f"SQLite error during initialization: {e}", exc_info=True)
157
+ except Exception as e:
158
+ logger.error(f"Error initializing database: {e}", exc_info=True)
136
159
  raise
137
160
 
138
161
  async def save_config(self, config: SharedLinkConfig) -> SharedLinkConfig:
@@ -304,6 +327,76 @@ class SQLiteSharedLinkStore(SharedLinkStoreInterface):
304
327
  logger.error(f"SQLite error saving feedback {record.feedback_id}: {e}", exc_info=True)
305
328
  raise
306
329
 
330
+ async def save_example(self, example: Any) -> Any:
331
+ """Persist an example record to SQLite."""
332
+ try:
333
+ example_dict = example.to_dict()
334
+ async with aiosqlite.connect(self.db_path) as db:
335
+ await db.execute(
336
+ """INSERT INTO examples (
337
+ example_id, agent_name, content, created_at, context_type
338
+ ) VALUES (?, ?, ?, ?, ?)""",
339
+ (
340
+ example_dict["example_id"],
341
+ example_dict["agent_name"],
342
+ example_dict["content"],
343
+ example_dict["created_at"],
344
+ example_dict["context_type"],
345
+ ),
346
+ )
347
+ await db.commit()
348
+ logger.info(f"Saved example {example_dict['example_id']} for agent {example_dict['agent_name']}")
349
+ return example
350
+ except sqlite3.Error as e:
351
+ logger.error(f"SQLite error saving example {example.example_id}: {e}", exc_info=True)
352
+ raise
353
+
354
+ async def get_example(self, id: str) -> Any | None:
355
+ """Get a single example record."""
356
+ try:
357
+ async with aiosqlite.connect(self.db_path) as db, db.execute(
358
+ """SELECT example_id, agent_name, content, created_at FROM examples WHERE example_id = ?""",
359
+ (id,)
360
+ ) as cursor:
361
+ row = await cursor.fetchone()
362
+ if row:
363
+ from flock.components.utility.example_utility_component import ExampleRecord
364
+ return ExampleRecord(
365
+ example_id=row[0],
366
+ agent_name=row[1],
367
+ content=row[2],
368
+ created_at=datetime.fromisoformat(row[3])
369
+ )
370
+ return None
371
+ except sqlite3.Error as e:
372
+ logger.error(f"SQLite error retrieving example {id}: {e}", exc_info=True)
373
+ return None
374
+
375
+ async def get_all_examples_for_agent(self, agent_name: str) -> list[Any]:
376
+ """Retrieve all example records from SQLite."""
377
+ try:
378
+ async with aiosqlite.connect(self.db_path) as db, db.execute(
379
+ """SELECT example_id, agent_name, content, created_at FROM examples WHERE agent_name = ? ORDER BY created_at DESC""",
380
+ (agent_name,)
381
+ ) as cursor:
382
+ rows = await cursor.fetchall()
383
+
384
+ examples = []
385
+ for row in rows:
386
+ from flock.components.utility.example_utility_component import ExampleRecord
387
+ examples.append(ExampleRecord(
388
+ example_id=row[0],
389
+ agent_name=row[1],
390
+ content=row[2],
391
+ created_at=datetime.fromisoformat(row[3])
392
+ ))
393
+
394
+ logger.debug(f"Retrieved {len(examples)} example records")
395
+ return examples
396
+ except sqlite3.Error as e:
397
+ logger.error(f"SQLite error retrieving all example records: {e}", exc_info=True)
398
+ return [] # Return empty list on error
399
+
307
400
 
308
401
  # ---------------------------------------------------------------------------
309
402
  # Azure Table + Blob implementation
@@ -568,6 +661,77 @@ class AzureTableSharedLinkStore(SharedLinkStoreInterface):
568
661
  )
569
662
  return records
570
663
 
664
+ # -------------------------------------------------------- save_example --
665
+ async def save_example(self, example: Any) -> Any:
666
+ """Persist an example record to Azure Table Storage."""
667
+ tbl_client = self.table_svc.get_table_client("flockexamples")
668
+
669
+ example_dict = example.to_dict()
670
+
671
+ entity = {
672
+ "PartitionKey": "examples",
673
+ "RowKey": example_dict["example_id"],
674
+ "agent_name": example_dict["agent_name"],
675
+ "content": example_dict["content"],
676
+ "created_at": example_dict["created_at"],
677
+ "context_type": example_dict["context_type"]
678
+ }
679
+
680
+ # ------------------------------------------------------------------ Table upsert
681
+ await tbl_client.upsert_entity(entity)
682
+ logger.info(f"Saved example {example_dict['example_id']} for agent {example_dict['agent_name']}")
683
+ return example
684
+
685
+ # -------------------------------------------------------- get_example --
686
+ async def get_example(self, id: str) -> Any | None:
687
+ """Retrieve a single example record from Azure Table Storage."""
688
+ tbl_client = self.table_svc.get_table_client("flockexamples")
689
+ try:
690
+ entity = await tbl_client.get_entity("examples", id)
691
+ except ResourceNotFoundError:
692
+ logger.debug("No example record found for ID: %s", id)
693
+ return None
694
+
695
+ from flock.components.utility.example_utility_component import ExampleRecord
696
+ return ExampleRecord(
697
+ example_id=id,
698
+ agent_name=entity["agent_name"],
699
+ content=entity["content"],
700
+ created_at=entity["created_at"]
701
+ )
702
+
703
+ # ------------------------------------------- get_all_examples_for_agent --
704
+ async def get_all_examples_for_agent(self, agent_name: str) -> list[Any]:
705
+ """Retrieve all example records from Azure Table Storage for a specific agent."""
706
+ tbl_client = self.table_svc.get_table_client("flockexamples")
707
+
708
+ # Use Azure Table Storage filtering to only get records for the specified agent
709
+ escaped_agent_name = agent_name.replace("'", "''")
710
+ filter_query = f"agent_name eq '{escaped_agent_name}'"
711
+
712
+ logger.debug(f"Querying example records with filter: {filter_query}")
713
+
714
+ examples = []
715
+ try:
716
+ async for entity in tbl_client.query_entities(filter_query):
717
+ from flock.components.utility.example_utility_component import ExampleRecord
718
+ examples.append(ExampleRecord(
719
+ example_id=entity["RowKey"],
720
+ agent_name=entity["agent_name"],
721
+ content=entity["content"],
722
+ created_at=entity["created_at"]
723
+ ))
724
+
725
+ logger.debug("Retrieved %d example records for agent %s", len(examples), agent_name)
726
+ return examples
727
+
728
+ except Exception as e:
729
+ # Log the error.
730
+ logger.error(
731
+ f"Unable to query example entries for agent {agent_name}. Exception: {e}"
732
+ )
733
+ return examples
734
+
571
735
 
572
736
  # ----------------------- Factory Function -----------------------
573
737
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flock-core
3
- Version: 0.5.0b26
3
+ Version: 0.5.0b28
4
4
  Summary: Declarative LLM Orchestration at Scale
5
5
  Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
6
6
  License-File: LICENSE
@@ -27,23 +27,25 @@ flock/cli/yaml_editor.py,sha256=K3N0bh61G1TSDAZDnurqW9e_-hO6CtSQKXQqlDhCjVo,1252
27
27
  flock/cli/assets/release_notes.md,sha256=bqnk50jxM3w5uY44Dc7MkdT8XmRREFxrVBAG9XCOSSU,4896
28
28
  flock/components/__init__.py,sha256=qDcaP0O7_b5RlUEXluqwskpKCkhM73kSMeNXReze63M,963
29
29
  flock/components/evaluation/__init__.py,sha256=_M3UlRFeNN90fEny6byt5VdLDE5o5khbd0EPT0o9S9k,303
30
- flock/components/evaluation/declarative_evaluation_component.py,sha256=SiW6NddBsNNLte3sPiqkLe-sPCH1ACCyximhZoUsvpY,20706
30
+ flock/components/evaluation/declarative_evaluation_component.py,sha256=tEMs5mENuQL84ZXJlQObvSygqajaJcu0LLOEKAdaYoE,23195
31
31
  flock/components/routing/__init__.py,sha256=BH_pFm9T6bUuf8HH4byDJ0dO0fzEVHv9m-ghUdDVdm0,542
32
32
  flock/components/routing/conditional_routing_component.py,sha256=WqZLMz-0Dhfb97xvttNrJCIVe6FNMLEQ2m4KQTDpIbI,21374
33
33
  flock/components/routing/default_routing_component.py,sha256=ZHt2Kjf-GHB5n7evU5NSGeQJ1Wuims5soeMswqaUb1E,3370
34
34
  flock/components/routing/llm_routing_component.py,sha256=SAaOFjlnhnenM6QEBn3WIpjjNXO-tFpP44TS73zvqzQ,7502
35
- flock/components/utility/__init__.py,sha256=JRj932upddjzZMWs1avOupEFr_GZNu21ac66Rhw_XgY,532
35
+ flock/components/utility/__init__.py,sha256=FRgYC06ko6mlNiGDCpYCez_61LQ4s7YJKI2Rys8Ba6w,861
36
+ flock/components/utility/example_utility_component.py,sha256=PUbObpFaBG8dtM3llZemjT9RS_R_wsolZ2bqqrHB6-8,9206
37
+ flock/components/utility/feedback_utility_component.py,sha256=XsE-em-KGvrkwQeDvNrzliSlvIGb9EoikKSn7kgiK4c,8144
36
38
  flock/components/utility/memory_utility_component.py,sha256=26Io61bbCGjD8UQ4BltMA5RLkMXp8tQoQmddXbQSrzA,20183
37
39
  flock/components/utility/metrics_utility_component.py,sha256=Mck_sFCkfXvNpoSgW2N_WOLnjxazzx8jh79tIx5zJhw,24635
38
40
  flock/components/utility/output_utility_component.py,sha256=TdHhY5qJJDUk-_LK54zAFMSG_Zafe-UiEkwiJwPjfh0,8063
39
41
  flock/core/__init__.py,sha256=OkjsVjRkAB-I6ibeTKVikZ3MxLIcTIzWKphHTbzbr7s,3231
40
42
  flock/core/flock.py,sha256=wRycQlGeaq-Vd75mFpPe02qyWTOEyXthT873iBhA3TI,23388
41
43
  flock/core/flock_agent.py,sha256=4Vdhyk-rdsPEuN3xYBsLBBsfpklad6bNj_it9r6XIDc,12868
42
- flock/core/flock_factory.py,sha256=Z6GJpYXN9_DXuOqvBH9ir0SMoUw78DkWhrhkm90luAQ,20910
44
+ flock/core/flock_factory.py,sha256=1EI4lj9SDlNAR1RSg1-39zevDjXe9RRn37CsQbk2MoA,24145
43
45
  flock/core/flock_scheduler.py,sha256=ng_s7gyijmc-AmYvBn5rtg61CSUZiIkXPRSlA1xO6VQ,8766
44
46
  flock/core/flock_server_manager.py,sha256=tM_nOs37vAbEvxmhwy_DL2JPvgFViWroNxrRSu5MfUQ,4523
45
47
  flock/core/agent/__init__.py,sha256=l32KFMJnC_gidMXpAXK8-OX228bWOhNc8OY_NzXm59Q,515
46
- flock/core/agent/default_agent.py,sha256=924SWDx8axJ57JCWREZuLzV8039Wt_-5WIBNTvx479Y,7483
48
+ flock/core/agent/default_agent.py,sha256=Y_Kd-ziScW3o1M_q9z2NfAIaHtMuvYQjwF-Hn7ySbpY,9126
47
49
  flock/core/agent/flock_agent_components.py,sha256=LamOgpRC7wDKuU3d6enDG0UFlNxyKPErLpH7SQ_Pi74,4539
48
50
  flock/core/agent/flock_agent_execution.py,sha256=pdOddBGv8y1P89Ix8XFWa1eW9i3bWjOYiQQxeY2K0yo,4217
49
51
  flock/core/agent/flock_agent_integration.py,sha256=fnxzEA8-gIopHwD1de8QKt2A7Ilb1iH5Koxk1uiASas,10737
@@ -80,7 +82,7 @@ flock/core/logging/telemetry.py,sha256=2T_o5qjvWWGMEP3UmlF9pbiTr4HDUcojHNrAbsad0
80
82
  flock/core/logging/trace_and_logged.py,sha256=5vNrK1kxuPMoPJ0-QjQg-EDJL1oiEzvU6UNi6X8FiMs,2117
81
83
  flock/core/logging/formatters/enum_builder.py,sha256=LgEYXUv84wK5vwHflZ5h8HBGgvLH3sByvUQe8tZiyY0,981
82
84
  flock/core/logging/formatters/theme_builder.py,sha256=Wnaal3HuUDA4HFg9tdql1BxYwK83ACOZBBQy-DXnxcA,17342
83
- flock/core/logging/formatters/themed_formatter.py,sha256=f9BiIBUk3cLma6eAPbW8BnvUqTzPzcPhjLNQoia7pI4,20656
85
+ flock/core/logging/formatters/themed_formatter.py,sha256=7SjkayQINY7ttxcqMWeZ0mxrqXWq6tgUgeEPKeLgddk,20888
84
86
  flock/core/logging/formatters/themes.py,sha256=80BRJJB0LZr11N0yQw2f8vdb_9179qjQO8PoeBaLMN0,10680
85
87
  flock/core/logging/span_middleware/baggage_span_processor.py,sha256=gJfRl8FeB6jdtghTaRHCrOaTo4fhPMRKgjqtZj-8T48,1118
86
88
  flock/core/logging/telemetry_exporter/base_exporter.py,sha256=rQJJzS6q9n2aojoSqwCnl7ZtHrh5LZZ-gkxUuI5WfrQ,1124
@@ -497,7 +499,7 @@ flock/webapp/app/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
497
499
  flock/webapp/app/services/feedback_file_service.py,sha256=6WYJjml8lt_ULH5vq7JSWrPQPvUSLvp91qMBt-_tg5Q,9376
498
500
  flock/webapp/app/services/flock_service.py,sha256=a2gcmx7_8uxSnu_Y3IlEl6e-JbeWO5_ejDyE5yOKVeA,14929
499
501
  flock/webapp/app/services/sharing_models.py,sha256=XeJk1akILV_1l-cIUaG8k_eYhjV3EWBCWZ2kpwbdImA,3609
500
- flock/webapp/app/services/sharing_store.py,sha256=Ee7D-2g44oM_PixxEuN1oqe1PmBqONHvfo3LY7SMlzY,27164
502
+ flock/webapp/app/services/sharing_store.py,sha256=eFcNzfLrMmmjXJkvbJQt3SeKoNyVKqRR-QMXl_AVlos,33929
501
503
  flock/webapp/app/templates/theme_mapper.html,sha256=z8ZY7nmk6PiUGzD_-px7wSXcEnuBM121rMq6u-2oaCo,14249
502
504
  flock/webapp/static/css/chat.css,sha256=Njc9gXfQzbXMrqtFJH2Yda-IQlwNPd2z4apXxzfA0sY,8169
503
505
  flock/webapp/static/css/components.css,sha256=WnicEHy3ptPzggKmyG9_oZp3X30EMJBUW3KEXaiUCUE,6018
@@ -552,8 +554,8 @@ flock/workflow/agent_execution_activity.py,sha256=0exwmeWKYXXxdUqDf4YaUVpn0zl06S
552
554
  flock/workflow/flock_workflow.py,sha256=sKFsRIL_bDGonXSNhK1zwu6UechghC_PihJJMidI-VI,9139
553
555
  flock/workflow/temporal_config.py,sha256=3_8O7SDEjMsSMXsWJBfnb6XTp0TFaz39uyzSlMTSF_I,3988
554
556
  flock/workflow/temporal_setup.py,sha256=KR6MlWOrpMtv8NyhaIPAsfl4tjobt81OBByQvg8Kw-Y,1948
555
- flock_core-0.5.0b26.dist-info/METADATA,sha256=zJZHhoco6VnScWx6VOAZoCGsIOkMqEkqX2p_Y_RooxQ,9997
556
- flock_core-0.5.0b26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
557
- flock_core-0.5.0b26.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
558
- flock_core-0.5.0b26.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
559
- flock_core-0.5.0b26.dist-info/RECORD,,
557
+ flock_core-0.5.0b28.dist-info/METADATA,sha256=X_aEWYlTDI-nVJnkxCKu_4OKBMSS604qO5UHVeFn56U,9997
558
+ flock_core-0.5.0b28.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
559
+ flock_core-0.5.0b28.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
560
+ flock_core-0.5.0b28.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
561
+ flock_core-0.5.0b28.dist-info/RECORD,,