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

@@ -10,9 +10,9 @@ from fastapi import ( # Ensure Form and HTTPException are imported
10
10
  Form,
11
11
  Request,
12
12
  )
13
+ from fastapi.encoders import jsonable_encoder
13
14
  from fastapi.responses import HTMLResponse
14
15
  from fastapi.templating import Jinja2Templates
15
- from pydantic import BaseModel
16
16
 
17
17
  if TYPE_CHECKING:
18
18
  from flock.core.flock import Flock
@@ -152,10 +152,13 @@ async def htmx_run_flock(
152
152
  return HTMLResponse(f"<p class='error'>Error processing inputs for {start_agent_name}: {e_parse}</p>")
153
153
 
154
154
  result_data = await run_current_flock_service(start_agent_name, inputs, request.app.state)
155
- if isinstance(result_data, BaseModel):
156
- raw_json_for_template = result_data.model_dump_json(indent=2, ensure_ascii=False)
157
- else:
158
- raw_json_for_template = json.dumps(result_data, indent=2, ensure_ascii=False)
155
+
156
+
157
+ raw_json_for_template = json.dumps(
158
+ jsonable_encoder(result_data), # ← converts every nested BaseModel, datetime, etc.
159
+ indent=2,
160
+ ensure_ascii=False
161
+ )
159
162
  # Unescape newlines for proper display in HTML <pre> tag
160
163
  result_data_raw_json_str = raw_json_for_template.replace('\\n', '\n')
161
164
  root_path = request.scope.get("root_path", "")
@@ -219,10 +222,11 @@ async def htmx_run_shared_flock(
219
222
 
220
223
  shared_logger.info(f"HTMX Run Shared: Executing agent '{start_agent_name}' in pre-loaded Flock '{temp_flock.name}'. Inputs: {list(inputs.keys())}")
221
224
  result_data = await temp_flock.run_async(start_agent=start_agent_name, input=inputs, box_result=False)
222
- if isinstance(result_data, BaseModel):
223
- raw_json_for_template = result_data.model_dump_json(indent=2, ensure_ascii=False)
224
- else:
225
- raw_json_for_template = json.dumps(result_data, indent=2, ensure_ascii=False)
225
+ raw_json_for_template = json.dumps(
226
+ jsonable_encoder(result_data), # converts every nested BaseModel, datetime, etc.
227
+ indent=2,
228
+ ensure_ascii=False
229
+ )
226
230
  # Unescape newlines for proper display in HTML <pre> tag
227
231
  result_data_raw_json_str = raw_json_for_template.replace('\\n', '\n')
228
232
  shared_logger.info(f"HTMX Run Shared: Agent '{start_agent_name}' executed. Result keys: {list(result_data.keys()) if isinstance(result_data, dict) else 'N/A'}")
@@ -227,136 +227,155 @@ class SQLiteSharedLinkStore(SharedLinkStoreInterface):
227
227
  except sqlite3.Error as e:
228
228
  logger.error(f"SQLite error saving feedback {record.feedback_id}: {e}", exc_info=True)
229
229
  raise
230
+ # flock/webapp/app/services/sharing_store.py ← replace only this class
231
+
232
+ # ---------------------------------------------------------------------------
233
+ # Azure Table + Blob implementation
234
+ # ---------------------------------------------------------------------------
235
+
236
+ try:
237
+ from azure.storage.blob.aio import BlobServiceClient
238
+ AZURE_BLOB_AVAILABLE = True
239
+ except ImportError: # blob SDK not installed
240
+ AZURE_BLOB_AVAILABLE = False
241
+ BlobServiceClient = None
230
242
 
231
243
  class AzureTableSharedLinkStore(SharedLinkStoreInterface):
232
- """Azure Table Storage implementation for storing and retrieving shared link configurations."""
244
+ """Store configs in Azure Table; store large flock YAML in Blob Storage."""
245
+
246
+ _TABLE_NAME = "flocksharedlinks"
247
+ _FEEDBACK_TBL_NAME = "flockfeedback"
248
+ _CONTAINER_NAME = "flocksharedlinkdefs" # blobs live here
249
+ _PARTITION_KEY = "shared_links"
233
250
 
234
251
  def __init__(self, connection_string: str):
235
- """Initialize Azure Table Storage store with connection string."""
236
252
  if not AZURE_AVAILABLE:
237
- raise ImportError("Azure Table Storage dependencies not available. Install with: pip install azure-data-tables")
253
+ raise ImportError("pip install azure-data-tables")
254
+ if not AZURE_BLOB_AVAILABLE:
255
+ raise ImportError("pip install azure-storage-blob")
238
256
 
239
257
  self.connection_string = connection_string
240
- self.table_service_client = TableServiceClient.from_connection_string(connection_string)
241
- self.shared_links_table_name = "flocksharedlinks"
242
- self.feedback_table_name = "flockfeedback"
243
- logger.info("AzureTableSharedLinkStore initialized")
258
+ self.table_svc = TableServiceClient.from_connection_string(connection_string)
259
+ self.blob_svc = BlobServiceClient.from_connection_string(connection_string)
244
260
 
261
+ # ------------------------------------------------------------------ init
245
262
  async def initialize(self) -> None:
246
- """Initializes the Azure Tables (creates them if they don't exist)."""
263
+ # 1. Azure Tables ----------------------------------------------------
247
264
  try:
248
- # Create shared_links table
249
- try:
250
- await self.table_service_client.create_table(self.shared_links_table_name)
251
- logger.info(f"Created Azure Table: {self.shared_links_table_name}")
252
- except ResourceExistsError:
253
- logger.debug(f"Azure Table already exists: {self.shared_links_table_name}")
254
-
255
- # Create feedback table
256
- try:
257
- await self.table_service_client.create_table(self.feedback_table_name)
258
- logger.info(f"Created Azure Table: {self.feedback_table_name}")
259
- except ResourceExistsError:
260
- logger.debug(f"Azure Table already exists: {self.feedback_table_name}")
261
-
262
- logger.info("Azure Table Storage initialized successfully")
263
- except Exception as e:
264
- logger.error(f"Error initializing Azure Table Storage: {e}", exc_info=True)
265
- raise
265
+ await self.table_svc.create_table(self._TABLE_NAME)
266
+ logger.info("Created Azure Table '%s'", self._TABLE_NAME)
267
+ except ResourceExistsError:
268
+ logger.debug("Azure Table '%s' already exists", self._TABLE_NAME)
266
269
 
267
- async def save_config(self, config: SharedLinkConfig) -> SharedLinkConfig:
268
- """Saves a shared link configuration to Azure Table Storage."""
269
270
  try:
270
- table_client = self.table_service_client.get_table_client(self.shared_links_table_name)
271
-
272
- entity = {
273
- "PartitionKey": "shared_links", # Use a fixed partition key for simplicity
274
- "RowKey": config.share_id,
275
- "share_id": config.share_id,
276
- "agent_name": config.agent_name,
277
- "flock_definition": config.flock_definition,
278
- "created_at": config.created_at.isoformat(),
279
- "share_type": config.share_type,
280
- "chat_message_key": config.chat_message_key,
281
- "chat_history_key": config.chat_history_key,
282
- "chat_response_key": config.chat_response_key,
283
- }
284
-
285
- await table_client.upsert_entity(entity)
286
- logger.info(f"Saved shared link config to Azure Table Storage for ID: {config.share_id} with type: {config.share_type}")
287
- return config
288
- except Exception as e:
289
- logger.error(f"Error saving config to Azure Table Storage for ID {config.share_id}: {e}", exc_info=True)
290
- raise
271
+ await self.table_svc.create_table(self._FEEDBACK_TBL_NAME)
272
+ logger.info("Created Azure Table '%s'", self._FEEDBACK_TBL_NAME)
273
+ except ResourceExistsError:
274
+ logger.debug("Azure Table '%s' already exists", self._FEEDBACK_TBL_NAME)
275
+
276
+ # 2. Blob container --------------------------------------------------
277
+ try:
278
+ await self.blob_svc.create_container(self._CONTAINER_NAME)
279
+ logger.info("Created Blob container '%s'", self._CONTAINER_NAME)
280
+ except ResourceExistsError:
281
+ logger.debug("Blob container '%s' already exists", self._CONTAINER_NAME)
291
282
 
283
+ # ------------------------------------------------------------- save_config
284
+ async def save_config(self, config: SharedLinkConfig) -> SharedLinkConfig:
285
+ """Upload YAML to Blob, then upsert table row containing the blob name."""
286
+ blob_name = f"{config.share_id}.yaml"
287
+ blob_client = self.blob_svc.get_blob_client(self._CONTAINER_NAME, blob_name)
288
+
289
+ # 1. Upload flock_definition (overwrite in case of retry)
290
+ await blob_client.upload_blob(config.flock_definition,
291
+ overwrite=True,
292
+ content_type="text/yaml")
293
+ logger.debug("Uploaded blob '%s' (%d bytes)",
294
+ blob_name, len(config.flock_definition.encode()))
295
+
296
+ # 2. Persist lightweight record in the table
297
+ tbl_client = self.table_svc.get_table_client(self._TABLE_NAME)
298
+ entity = {
299
+ "PartitionKey": self._PARTITION_KEY,
300
+ "RowKey": config.share_id,
301
+ "agent_name": config.agent_name,
302
+ "created_at": config.created_at.isoformat(),
303
+ "share_type": config.share_type,
304
+ "chat_message_key": config.chat_message_key,
305
+ "chat_history_key": config.chat_history_key,
306
+ "chat_response_key": config.chat_response_key,
307
+ # NEW – just a few bytes, well under 64 KiB
308
+ "flock_blob_name": blob_name,
309
+ }
310
+ await tbl_client.upsert_entity(entity)
311
+ logger.info("Saved shared link %s → blob '%s'", config.share_id, blob_name)
312
+ return config
313
+
314
+ # -------------------------------------------------------------- get_config
292
315
  async def get_config(self, share_id: str) -> SharedLinkConfig | None:
293
- """Retrieves a shared link configuration from Azure Table Storage by its ID."""
316
+ tbl_client = self.table_svc.get_table_client(self._TABLE_NAME)
294
317
  try:
295
- table_client = self.table_service_client.get_table_client(self.shared_links_table_name)
296
-
297
- entity = await table_client.get_entity(partition_key="shared_links", row_key=share_id)
298
-
299
- logger.debug(f"Retrieved shared link config from Azure Table Storage for ID: {share_id}")
300
- return SharedLinkConfig(
301
- share_id=entity["share_id"],
302
- agent_name=entity["agent_name"],
303
- created_at=entity["created_at"], # Pydantic will parse from ISO format
304
- flock_definition=entity["flock_definition"],
305
- share_type=entity.get("share_type", "agent_run"),
306
- chat_message_key=entity.get("chat_message_key"),
307
- chat_history_key=entity.get("chat_history_key"),
308
- chat_response_key=entity.get("chat_response_key"),
309
- )
318
+ entity = await tbl_client.get_entity(self._PARTITION_KEY, share_id)
310
319
  except ResourceNotFoundError:
311
- logger.debug(f"No shared link config found in Azure Table Storage for ID: {share_id}")
320
+ logger.debug("No config entity for id '%s'", share_id)
312
321
  return None
322
+
323
+ blob_name = entity["flock_blob_name"]
324
+ blob_client = self.blob_svc.get_blob_client(self._CONTAINER_NAME, blob_name)
325
+ try:
326
+ blob_bytes = await (await blob_client.download_blob()).readall()
327
+ flock_yaml = blob_bytes.decode()
313
328
  except Exception as e:
314
- logger.error(f"Error retrieving config from Azure Table Storage for ID {share_id}: {e}", exc_info=True)
315
- return None
329
+ logger.error("Cannot download blob '%s' for share_id=%s: %s",
330
+ blob_name, share_id, e, exc_info=True)
331
+ raise
316
332
 
333
+ return SharedLinkConfig(
334
+ share_id = share_id,
335
+ agent_name = entity["agent_name"],
336
+ created_at = entity["created_at"],
337
+ flock_definition = flock_yaml,
338
+ share_type = entity.get("share_type", "agent_run"),
339
+ chat_message_key = entity.get("chat_message_key"),
340
+ chat_history_key = entity.get("chat_history_key"),
341
+ chat_response_key = entity.get("chat_response_key"),
342
+ )
343
+
344
+ # ----------------------------------------------------------- delete_config
317
345
  async def delete_config(self, share_id: str) -> bool:
318
- """Deletes a shared link configuration from Azure Table Storage by its ID."""
346
+ tbl_client = self.table_svc.get_table_client(self._TABLE_NAME)
319
347
  try:
320
- table_client = self.table_service_client.get_table_client(self.shared_links_table_name)
321
-
322
- await table_client.delete_entity(partition_key="shared_links", row_key=share_id)
323
- logger.info(f"Deleted shared link config from Azure Table Storage for ID: {share_id}")
324
- return True
348
+ entity = await tbl_client.get_entity(self._PARTITION_KEY, share_id)
325
349
  except ResourceNotFoundError:
326
- logger.info(f"Attempted to delete non-existent shared link config from Azure Table Storage for ID: {share_id}")
327
- return False
328
- except Exception as e:
329
- logger.error(f"Error deleting config from Azure Table Storage for ID {share_id}: {e}", exc_info=True)
350
+ logger.info("Delete: entity %s not found", share_id)
330
351
  return False
331
352
 
332
- # ----------------------- Feedback methods -----------------------
353
+ # 1. Remove blob (ignore missing blob)
354
+ blob_name = entity["flock_blob_name"]
355
+ blob_client = self.blob_svc.get_blob_client(self._CONTAINER_NAME, blob_name)
356
+ try:
357
+ await blob_client.delete_blob(delete_snapshots="include")
358
+ logger.debug("Deleted blob '%s'", blob_name)
359
+ except ResourceNotFoundError:
360
+ logger.warning("Blob '%s' already gone", blob_name)
361
+
362
+ # 2. Remove table row
363
+ await tbl_client.delete_entity(self._PARTITION_KEY, share_id)
364
+ logger.info("Deleted shared link %s and its blob", share_id)
365
+ return True
333
366
 
367
+ # -------------------------------------------------------- save_feedback --
334
368
  async def save_feedback(self, record: FeedbackRecord) -> FeedbackRecord:
335
- """Persist a feedback record to Azure Table Storage."""
336
- try:
337
- table_client = self.table_service_client.get_table_client(self.feedback_table_name)
338
-
339
- entity = {
340
- "PartitionKey": "feedback", # Use a fixed partition key for simplicity
341
- "RowKey": record.feedback_id,
342
- "feedback_id": record.feedback_id,
343
- "share_id": record.share_id,
344
- "context_type": record.context_type,
345
- "reason": record.reason,
346
- "expected_response": record.expected_response,
347
- "actual_response": record.actual_response,
348
- "flock_name": record.flock_name,
349
- "agent_name": record.agent_name,
350
- "flock_definition": record.flock_definition,
351
- "created_at": record.created_at.isoformat(),
352
- }
353
-
354
- await table_client.upsert_entity(entity)
355
- logger.info(f"Saved feedback to Azure Table Storage: {record.feedback_id} (share={record.share_id})")
356
- return record
357
- except Exception as e:
358
- logger.error(f"Error saving feedback to Azure Table Storage {record.feedback_id}: {e}", exc_info=True)
359
- raise
369
+ tbl_client = self.table_svc.get_table_client(self._FEEDBACK_TBL_NAME)
370
+ entity = {
371
+ "PartitionKey": "feedback",
372
+ "RowKey": record.feedback_id,
373
+ **record.model_dump(exclude={"feedback_id"}) # all other fields
374
+ }
375
+ await tbl_client.upsert_entity(entity)
376
+ logger.info("Saved feedback %s", record.feedback_id)
377
+ return record
378
+
360
379
 
361
380
 
362
381
  # ----------------------- Factory Function -----------------------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flock-core
3
- Version: 0.4.522
3
+ Version: 0.4.524
4
4
  Summary: Declarative LLM Orchestration at Scale
5
5
  Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
6
6
  License-File: LICENSE
@@ -502,13 +502,13 @@ flock/webapp/app/theme_mapper.py,sha256=QzWwLWpED78oYp3FjZ9zxv1KxCyj43m8MZ0fhfzz
502
502
  flock/webapp/app/utils.py,sha256=RF8DMKKAj1XPmm4txUdo2OdswI1ATQ7cqUm6G9JFDzA,2942
503
503
  flock/webapp/app/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
504
504
  flock/webapp/app/api/agent_management.py,sha256=5xqO94QjjAYvxImyjKV9EGUQOvo4n3eqs7pGwGPSQJ4,10394
505
- flock/webapp/app/api/execution.py,sha256=COPHVpyzjhGACZuQsrrudweGE4bHgtrxR4hoAopI2BA,13497
505
+ flock/webapp/app/api/execution.py,sha256=EeOhpABZ1STcRKIa8pXRqWeqtD4KS8KAWTNYbVns2FQ,13432
506
506
  flock/webapp/app/api/flock_management.py,sha256=1o-6-36kTnUjI3am_BqLpdrcz0aqFXrxE-hQHIFcCsg,4869
507
507
  flock/webapp/app/api/registry_viewer.py,sha256=IoInxJiRR0yFlecG_l2_eRc6l35RQQyEDMG9BcBkipY,1020
508
508
  flock/webapp/app/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
509
509
  flock/webapp/app/services/flock_service.py,sha256=olU1My3YYkrTCVIOYPgRted-8YgAop-Yi7G4gbRHTrg,14941
510
510
  flock/webapp/app/services/sharing_models.py,sha256=XeJk1akILV_1l-cIUaG8k_eYhjV3EWBCWZ2kpwbdImA,3609
511
- flock/webapp/app/services/sharing_store.py,sha256=qegEx2rbhlhJgxGjZ-5MJXCnxDBYoPnfL0THcobuEIk,17816
511
+ flock/webapp/app/services/sharing_store.py,sha256=Ogc2MWFS1FDu8GQ89txMP32DvWZ5NcJjQAv4mwEroYs,18121
512
512
  flock/webapp/app/templates/theme_mapper.html,sha256=z8ZY7nmk6PiUGzD_-px7wSXcEnuBM121rMq6u-2oaCo,14249
513
513
  flock/webapp/static/css/chat.css,sha256=Njc9gXfQzbXMrqtFJH2Yda-IQlwNPd2z4apXxzfA0sY,8169
514
514
  flock/webapp/static/css/components.css,sha256=WnicEHy3ptPzggKmyG9_oZp3X30EMJBUW3KEXaiUCUE,6018
@@ -562,8 +562,8 @@ flock/workflow/agent_execution_activity.py,sha256=Gy6FtuVAjf0NiUXmC3syS2eJpNQF4R
562
562
  flock/workflow/flock_workflow.py,sha256=iSUF_soFvWar0ffpkzE4irkDZRx0p4HnwmEBi_Ne2sY,9666
563
563
  flock/workflow/temporal_config.py,sha256=3_8O7SDEjMsSMXsWJBfnb6XTp0TFaz39uyzSlMTSF_I,3988
564
564
  flock/workflow/temporal_setup.py,sha256=YIHnSBntzOchHfMSh8hoLeNXrz3B1UbR14YrR6soM7A,1606
565
- flock_core-0.4.522.dist-info/METADATA,sha256=ihZdtIEwkGF3FUhglU0fQo9EYJEZSTpqB3m10FlgtSk,22786
566
- flock_core-0.4.522.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
567
- flock_core-0.4.522.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
568
- flock_core-0.4.522.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
569
- flock_core-0.4.522.dist-info/RECORD,,
565
+ flock_core-0.4.524.dist-info/METADATA,sha256=hD_opwGCMB2Y8gDQGmnS9w_XRNKQwzCF65_EeXmjUMU,22786
566
+ flock_core-0.4.524.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
567
+ flock_core-0.4.524.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
568
+ flock_core-0.4.524.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
569
+ flock_core-0.4.524.dist-info/RECORD,,