flock-core 0.4.523__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.

@@ -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.523
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
@@ -508,7 +508,7 @@ flock/webapp/app/api/registry_viewer.py,sha256=IoInxJiRR0yFlecG_l2_eRc6l35RQQyED
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.523.dist-info/METADATA,sha256=vpIiEYBpEyuBEwT9iQ7eU70WzJT2OMmetWqBLYfncc0,22786
566
- flock_core-0.4.523.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
567
- flock_core-0.4.523.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
568
- flock_core-0.4.523.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
569
- flock_core-0.4.523.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,,