flock-core 0.4.0b46__py3-none-any.whl → 0.4.0b49__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.

Files changed (50) hide show
  1. flock/__init__.py +45 -3
  2. flock/core/flock.py +105 -61
  3. flock/core/flock_registry.py +45 -38
  4. flock/core/util/spliter.py +4 -0
  5. flock/evaluators/__init__.py +1 -0
  6. flock/evaluators/declarative/__init__.py +1 -0
  7. flock/modules/__init__.py +1 -0
  8. flock/modules/assertion/__init__.py +1 -0
  9. flock/modules/callback/__init__.py +1 -0
  10. flock/modules/mem0/__init__.py +1 -0
  11. flock/modules/mem0/mem0_module.py +63 -0
  12. flock/modules/mem0graph/__init__.py +1 -0
  13. flock/modules/mem0graph/mem0_graph_module.py +63 -0
  14. flock/modules/memory/__init__.py +1 -0
  15. flock/modules/output/__init__.py +1 -0
  16. flock/modules/performance/__init__.py +1 -0
  17. flock/tools/__init__.py +188 -0
  18. flock/{core/tools → tools}/azure_tools.py +284 -0
  19. flock/tools/code_tools.py +56 -0
  20. flock/tools/file_tools.py +140 -0
  21. flock/{core/tools/dev_tools/github.py → tools/github_tools.py} +3 -3
  22. flock/{core/tools → tools}/markdown_tools.py +14 -4
  23. flock/tools/system_tools.py +9 -0
  24. flock/{core/tools/llm_tools.py → tools/text_tools.py} +47 -25
  25. flock/tools/web_tools.py +90 -0
  26. flock/{core/tools → tools}/zendesk_tools.py +6 -6
  27. flock/webapp/app/api/execution.py +130 -30
  28. flock/webapp/app/chat.py +303 -16
  29. flock/webapp/app/config.py +15 -1
  30. flock/webapp/app/dependencies.py +22 -0
  31. flock/webapp/app/main.py +509 -18
  32. flock/webapp/app/services/flock_service.py +38 -13
  33. flock/webapp/app/services/sharing_models.py +43 -0
  34. flock/webapp/app/services/sharing_store.py +156 -0
  35. flock/webapp/static/css/chat.css +57 -0
  36. flock/webapp/templates/chat.html +29 -4
  37. flock/webapp/templates/partials/_chat_messages.html +1 -1
  38. flock/webapp/templates/partials/_chat_settings_form.html +22 -0
  39. flock/webapp/templates/partials/_execution_form.html +28 -1
  40. flock/webapp/templates/partials/_share_chat_link_snippet.html +11 -0
  41. flock/webapp/templates/partials/_share_link_snippet.html +35 -0
  42. flock/webapp/templates/shared_run_page.html +116 -0
  43. flock/workflow/activities.py +1 -0
  44. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/METADATA +27 -14
  45. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/RECORD +48 -28
  46. flock/core/tools/basic_tools.py +0 -317
  47. flock/modules/zep/zep_module.py +0 -187
  48. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/WHEEL +0 -0
  49. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/entry_points.txt +0 -0
  50. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,188 @@
1
+ from .azure_tools import (
2
+ azure_search_create_index,
3
+ azure_search_create_vector_index,
4
+ azure_search_delete_documents,
5
+ azure_search_get_document,
6
+ azure_search_get_index_statistics,
7
+ azure_search_initialize_clients,
8
+ azure_search_list_indexes,
9
+ azure_search_query,
10
+ azure_search_upload_documents,
11
+ azure_storage_create_container,
12
+ azure_storage_delete_blob,
13
+ azure_storage_delete_container,
14
+ azure_storage_download_blob_to_bytes,
15
+ azure_storage_download_blob_to_file,
16
+ azure_storage_download_blob_to_text,
17
+ azure_storage_get_blob_properties,
18
+ azure_storage_list_blobs,
19
+ azure_storage_list_containers,
20
+ azure_storage_upload_blob_bytes,
21
+ azure_storage_upload_blob_from_file,
22
+ azure_storage_upload_blob_text,
23
+ )
24
+ from .code_tools import code_code_eval, code_evaluate_math
25
+ from .file_tools import (
26
+ file_get_anything_as_markdown,
27
+ file_json_parse_safe,
28
+ file_json_search,
29
+ file_read_from_file,
30
+ file_save_to_file,
31
+ )
32
+ from .github_tools import (
33
+ github_create_files,
34
+ github_create_user_stories_as_github_issue,
35
+ github_upload_readme,
36
+ )
37
+ from .markdown_tools import (
38
+ markdown_extract_code_blocks,
39
+ markdown_extract_links,
40
+ markdown_extract_tables,
41
+ markdown_split_by_headers,
42
+ markdown_to_plain_text,
43
+ )
44
+ from .text_tools import (
45
+ text_calculate_hash,
46
+ text_chunking_for_embedding,
47
+ text_clean_text,
48
+ text_count_tokens,
49
+ text_count_tokens_estimate,
50
+ text_count_words,
51
+ text_detect_language,
52
+ text_extract_json_from_text,
53
+ text_extract_keywords,
54
+ text_extract_numbers,
55
+ text_extract_urls,
56
+ text_format_chat_history,
57
+ text_format_table_from_dicts,
58
+ text_recursive_splitter,
59
+ text_split_by_characters,
60
+ text_split_by_sentences,
61
+ text_split_by_separator,
62
+ text_split_by_tokens,
63
+ text_split_code_by_functions,
64
+ text_tiktoken_split,
65
+ text_truncate_to_token_limit,
66
+ )
67
+ from .web_tools import (
68
+ web_content_as_markdown,
69
+ web_search_bing,
70
+ web_search_duckduckgo,
71
+ web_search_tavily,
72
+ )
73
+ from .zendesk_tools import (
74
+ zendesk_get_article_by_id,
75
+ zendesk_get_articles,
76
+ zendesk_get_comments_by_ticket_id,
77
+ zendesk_get_ticket_by_id,
78
+ zendesk_get_tickets,
79
+ zendesk_search_articles,
80
+ )
81
+
82
+ storage_tools = [
83
+ azure_storage_list_containers,
84
+ azure_storage_create_container,
85
+ azure_storage_delete_container,
86
+ azure_storage_list_blobs,
87
+ azure_storage_upload_blob_text,
88
+ azure_storage_upload_blob_bytes,
89
+ azure_storage_upload_blob_from_file,
90
+ azure_storage_download_blob_to_text,
91
+ azure_storage_download_blob_to_bytes,
92
+ azure_storage_download_blob_to_file,
93
+ azure_storage_delete_blob,
94
+ azure_storage_get_blob_properties,
95
+ ]
96
+
97
+ azure_search_tools = [
98
+ azure_search_initialize_clients,
99
+ azure_search_create_index,
100
+ azure_search_upload_documents,
101
+ azure_search_query,
102
+ azure_search_get_document,
103
+ azure_search_delete_documents,
104
+ azure_search_list_indexes,
105
+ azure_search_get_index_statistics,
106
+ azure_search_create_vector_index,
107
+ ]
108
+
109
+ file_tools_collection = [
110
+ file_get_anything_as_markdown,
111
+ file_save_to_file,
112
+ file_read_from_file,
113
+ file_json_parse_safe,
114
+ file_json_search,
115
+ ]
116
+
117
+ code_tools_collection = [code_evaluate_math, code_code_eval]
118
+
119
+ web_tools_collection = [
120
+ web_content_as_markdown,
121
+ web_search_bing,
122
+ web_search_duckduckgo,
123
+ web_search_tavily,
124
+ ]
125
+
126
+ github_tools_collection = [
127
+ github_create_user_stories_as_github_issue,
128
+ github_upload_readme,
129
+ github_create_files,
130
+ ]
131
+
132
+ llm_processing_tools = [
133
+ text_split_by_sentences,
134
+ text_split_by_characters,
135
+ text_split_by_tokens,
136
+ text_split_by_separator,
137
+ text_recursive_splitter,
138
+ text_chunking_for_embedding,
139
+ text_split_code_by_functions,
140
+ text_count_tokens,
141
+ text_count_tokens_estimate,
142
+ text_truncate_to_token_limit,
143
+ text_extract_keywords,
144
+ text_clean_text,
145
+ text_format_chat_history,
146
+ text_extract_json_from_text,
147
+ text_calculate_hash,
148
+ text_format_table_from_dicts,
149
+ text_detect_language,
150
+ text_tiktoken_split,
151
+ text_count_words,
152
+ text_extract_urls,
153
+ text_extract_numbers,
154
+ ]
155
+
156
+ markdown_processing_tools = [
157
+ markdown_split_by_headers,
158
+ markdown_extract_code_blocks,
159
+ markdown_extract_links,
160
+ markdown_extract_tables,
161
+ markdown_to_plain_text,
162
+ ]
163
+
164
+ zendesk_tools_collection = [
165
+ zendesk_get_tickets,
166
+ zendesk_get_ticket_by_id,
167
+ zendesk_get_comments_by_ticket_id,
168
+ zendesk_get_article_by_id,
169
+ zendesk_get_articles,
170
+ zendesk_search_articles,
171
+ ]
172
+
173
+ __all__ = [
174
+ "azure_search_tools",
175
+ "code_tools_collection",
176
+ "file_tools_collection",
177
+ "github_tools_collection",
178
+ "llm_processing_tools",
179
+ "markdown_processing_tools",
180
+ "storage_tools",
181
+ "web_tools_collection",
182
+ "zendesk_tools_collection",
183
+ ]
184
+
185
+ # If there was existing content in __init__.py, this approach might overwrite it.
186
+ # A safer approach if __init__.py might exist and have other critical initializations
187
+ # would be to read it first, then append/modify.
188
+ # For now, assuming a fresh creation or simple __init__.py.
@@ -16,6 +16,10 @@ from azure.search.documents.indexes.models import (
16
16
  VectorSearchProfile,
17
17
  )
18
18
  from azure.search.documents.models import VectorizedQuery
19
+ from azure.storage.blob import (
20
+ BlobServiceClient,
21
+ ContentSettings,
22
+ )
19
23
 
20
24
  from flock.core.logging.trace_and_logged import traced_and_logged
21
25
 
@@ -495,3 +499,283 @@ def azure_search_create_vector_index(
495
499
  }
496
500
  except Exception as e:
497
501
  return {"error": str(e), "created": False}
502
+
503
+
504
+ # --- Azure Blob Storage Tools ---
505
+
506
+ def _get_blob_service_client(conn_string_env_var: str) -> BlobServiceClient:
507
+ """Helper function to get BlobServiceClient using a connection string from an environment variable."""
508
+ actual_connection_string = os.environ.get(conn_string_env_var)
509
+ if not actual_connection_string:
510
+ raise ValueError(f"Environment variable '{conn_string_env_var}' for Azure Storage connection string is not set or is empty.")
511
+ return BlobServiceClient.from_connection_string(actual_connection_string)
512
+
513
+
514
+ @traced_and_logged
515
+ def azure_storage_list_containers(conn_string_env_var: str) -> list[str]:
516
+ """Lists all containers in the Azure Storage account.
517
+
518
+ Args:
519
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
520
+
521
+ Returns:
522
+ A list of container names.
523
+ """
524
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
525
+ containers = blob_service_client.list_containers()
526
+ return [container.name for container in containers]
527
+
528
+
529
+ @traced_and_logged
530
+ def azure_storage_create_container(container_name: str, conn_string_env_var: str) -> dict[str, Any]:
531
+ """Creates a new container in the Azure Storage account.
532
+
533
+ Args:
534
+ container_name: The name of the container to create.
535
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
536
+
537
+ Returns:
538
+ A dictionary with creation status.
539
+ """
540
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
541
+ try:
542
+ blob_service_client.create_container(container_name)
543
+ return {"container_name": container_name, "created": True, "message": f"Container '{container_name}' created successfully."}
544
+ except Exception as e:
545
+ return {"container_name": container_name, "created": False, "error": str(e)}
546
+
547
+
548
+ @traced_and_logged
549
+ def azure_storage_delete_container(container_name: str, conn_string_env_var: str) -> dict[str, Any]:
550
+ """Deletes an existing container from the Azure Storage account.
551
+
552
+ Args:
553
+ container_name: The name of the container to delete.
554
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
555
+
556
+ Returns:
557
+ A dictionary with deletion status.
558
+ """
559
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
560
+ try:
561
+ blob_service_client.delete_container(container_name)
562
+ return {"container_name": container_name, "deleted": True, "message": f"Container '{container_name}' deleted successfully."}
563
+ except Exception as e:
564
+ return {"container_name": container_name, "deleted": False, "error": str(e)}
565
+
566
+
567
+ @traced_and_logged
568
+ def azure_storage_list_blobs(container_name: str, conn_string_env_var: str) -> list[str]:
569
+ """Lists all blobs in a specified container.
570
+
571
+ Args:
572
+ container_name: The name of the container.
573
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
574
+
575
+ Returns:
576
+ A list of blob names.
577
+ """
578
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
579
+ container_client = blob_service_client.get_container_client(container_name)
580
+ blob_list = container_client.list_blobs()
581
+ return [blob.name for blob in blob_list]
582
+
583
+
584
+ @traced_and_logged
585
+ def azure_storage_upload_blob_text(container_name: str, blob_name: str, text_content: str, conn_string_env_var: str, overwrite: bool = True) -> dict[str, Any]:
586
+ """Uploads text content as a blob to the specified container.
587
+
588
+ Args:
589
+ container_name: The name of the container.
590
+ blob_name: The name of the blob to create.
591
+ text_content: The string content to upload.
592
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
593
+ overwrite: Whether to overwrite the blob if it already exists. Defaults to True.
594
+
595
+ Returns:
596
+ A dictionary with upload status.
597
+ """
598
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
599
+ blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
600
+ try:
601
+ content_settings = ContentSettings(content_type='text/plain')
602
+ blob_client.upload_blob(text_content.encode('utf-8'), overwrite=overwrite, content_settings=content_settings)
603
+ return {"container_name": container_name, "blob_name": blob_name, "uploaded": True, "message": "Text content uploaded successfully."}
604
+ except Exception as e:
605
+ return {"container_name": container_name, "blob_name": blob_name, "uploaded": False, "error": str(e)}
606
+
607
+
608
+ @traced_and_logged
609
+ def azure_storage_upload_blob_bytes(container_name: str, blob_name: str, bytes_content: bytes, conn_string_env_var: str, overwrite: bool = True) -> dict[str, Any]:
610
+ """Uploads bytes content as a blob to the specified container.
611
+
612
+ Args:
613
+ container_name: The name of the container.
614
+ blob_name: The name of the blob to create.
615
+ bytes_content: The bytes content to upload.
616
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
617
+ overwrite: Whether to overwrite the blob if it already exists. Defaults to True.
618
+
619
+ Returns:
620
+ A dictionary with upload status.
621
+ """
622
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
623
+ blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
624
+ try:
625
+ content_settings = ContentSettings(content_type='application/octet-stream')
626
+ blob_client.upload_blob(bytes_content, overwrite=overwrite, content_settings=content_settings)
627
+ return {"container_name": container_name, "blob_name": blob_name, "uploaded": True, "message": "Bytes content uploaded successfully."}
628
+ except Exception as e:
629
+ return {"container_name": container_name, "blob_name": blob_name, "uploaded": False, "error": str(e)}
630
+
631
+
632
+ @traced_and_logged
633
+ def azure_storage_upload_blob_from_file(container_name: str, blob_name: str, file_path: str, conn_string_env_var: str, overwrite: bool = True) -> dict[str, Any]:
634
+ """Uploads a local file to a blob in the specified container.
635
+
636
+ Args:
637
+ container_name: The name of the container.
638
+ blob_name: The name of the blob to create.
639
+ file_path: The local path to the file to upload.
640
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
641
+ overwrite: Whether to overwrite the blob if it already exists. Defaults to True.
642
+
643
+ Returns:
644
+ A dictionary with upload status.
645
+ """
646
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
647
+ blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
648
+ try:
649
+ with open(file_path, "rb") as data:
650
+ blob_client.upload_blob(data, overwrite=overwrite)
651
+ return {"container_name": container_name, "blob_name": blob_name, "file_path": file_path, "uploaded": True, "message": "File uploaded successfully."}
652
+ except FileNotFoundError:
653
+ return {"container_name": container_name, "blob_name": blob_name, "file_path": file_path, "uploaded": False, "error": "File not found."}
654
+ except Exception as e:
655
+ return {"container_name": container_name, "blob_name": blob_name, "file_path": file_path, "uploaded": False, "error": str(e)}
656
+
657
+
658
+ @traced_and_logged
659
+ def azure_storage_download_blob_to_text(container_name: str, blob_name: str, conn_string_env_var: str) -> str:
660
+ """Downloads a blob's content as text.
661
+
662
+ Args:
663
+ container_name: The name of the container.
664
+ blob_name: The name of the blob to download.
665
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
666
+
667
+ Returns:
668
+ The blob content as a string.
669
+
670
+ Raises:
671
+ Exception: If download fails or blob is not text.
672
+ """
673
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
674
+ blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
675
+ try:
676
+ download_stream = blob_client.download_blob()
677
+ return download_stream.readall().decode('utf-8')
678
+ except Exception as e:
679
+ raise Exception(f"Failed to download or decode blob '{blob_name}' from container '{container_name}': {e!s}")
680
+
681
+
682
+ @traced_and_logged
683
+ def azure_storage_download_blob_to_bytes(container_name: str, blob_name: str, conn_string_env_var: str) -> bytes:
684
+ """Downloads a blob's content as bytes.
685
+
686
+ Args:
687
+ container_name: The name of the container.
688
+ blob_name: The name of the blob to download.
689
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
690
+
691
+ Returns:
692
+ The blob content as bytes.
693
+ """
694
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
695
+ blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
696
+ download_stream = blob_client.download_blob()
697
+ return download_stream.readall()
698
+
699
+
700
+ @traced_and_logged
701
+ def azure_storage_download_blob_to_file(container_name: str, blob_name: str, file_path: str, conn_string_env_var: str, overwrite: bool = True) -> dict[str, Any]:
702
+ """Downloads a blob to a local file.
703
+
704
+ Args:
705
+ container_name: The name of the container.
706
+ blob_name: The name of the blob to download.
707
+ file_path: The local path to save the downloaded file.
708
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
709
+ overwrite: Whether to overwrite the local file if it exists. Defaults to True.
710
+
711
+ Returns:
712
+ A dictionary with download status.
713
+ """
714
+ if not overwrite and os.path.exists(file_path):
715
+ return {"container_name": container_name, "blob_name": blob_name, "file_path": file_path, "downloaded": False, "error": "File exists and overwrite is False."}
716
+
717
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
718
+ blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
719
+ try:
720
+ with open(file_path, "wb") as download_file:
721
+ download_stream = blob_client.download_blob()
722
+ download_file.write(download_stream.readall())
723
+ return {"container_name": container_name, "blob_name": blob_name, "file_path": file_path, "downloaded": True, "message": "File downloaded successfully."}
724
+ except Exception as e:
725
+ return {"container_name": container_name, "blob_name": blob_name, "file_path": file_path, "downloaded": False, "error": str(e)}
726
+
727
+
728
+ @traced_and_logged
729
+ def azure_storage_delete_blob(container_name: str, blob_name: str, conn_string_env_var: str) -> dict[str, Any]:
730
+ """Deletes a specified blob from a container.
731
+
732
+ Args:
733
+ container_name: The name of the container.
734
+ blob_name: The name of the blob to delete.
735
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
736
+
737
+ Returns:
738
+ A dictionary with deletion status.
739
+ """
740
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
741
+ blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
742
+ try:
743
+ blob_client.delete_blob()
744
+ return {"container_name": container_name, "blob_name": blob_name, "deleted": True, "message": "Blob deleted successfully."}
745
+ except Exception as e:
746
+ return {"container_name": container_name, "blob_name": blob_name, "deleted": False, "error": str(e)}
747
+
748
+
749
+ @traced_and_logged
750
+ def azure_storage_get_blob_properties(container_name: str, blob_name: str, conn_string_env_var: str) -> dict[str, Any]:
751
+ """Retrieves properties of a specified blob.
752
+
753
+ Args:
754
+ container_name: The name of the container.
755
+ blob_name: The name of the blob.
756
+ conn_string_env_var: The name of the environment variable holding the Azure Storage connection string.
757
+
758
+ Returns:
759
+ A dictionary containing blob properties.
760
+ """
761
+ blob_service_client = _get_blob_service_client(conn_string_env_var)
762
+ blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
763
+ try:
764
+ properties = blob_client.get_blob_properties()
765
+ return {
766
+ "name": properties.name,
767
+ "container": properties.container,
768
+ "size": properties.size,
769
+ "content_type": properties.content_settings.content_type,
770
+ "last_modified": properties.last_modified.isoformat() if properties.last_modified else None,
771
+ "etag": properties.etag,
772
+ # Add more properties as needed
773
+ }
774
+ except Exception as e:
775
+ return {"container_name": container_name, "blob_name": blob_name, "error": str(e)}
776
+
777
+ # Potential future tools:
778
+ # - azure_storage_set_blob_metadata
779
+ # - azure_storage_get_blob_metadata
780
+ # - azure_storage_generate_sas_token_blob
781
+ # - azure_storage_copy_blob
@@ -0,0 +1,56 @@
1
+ from flock.core.interpreter.python_interpreter import PythonInterpreter
2
+ from flock.core.logging.trace_and_logged import traced_and_logged
3
+
4
+
5
+ @traced_and_logged
6
+ def code_evaluate_math(expression: str) -> float:
7
+ try:
8
+ result = PythonInterpreter(
9
+ {},
10
+ [
11
+ "os",
12
+ "math",
13
+ "random",
14
+ "datetime",
15
+ "time",
16
+ "string",
17
+ "collections",
18
+ "itertools",
19
+ "functools",
20
+ "typing",
21
+ "enum",
22
+ "json",
23
+ "ast",
24
+ ],
25
+ verbose=True,
26
+ ).execute(expression)
27
+ return result
28
+ except Exception:
29
+ raise
30
+
31
+
32
+ @traced_and_logged
33
+ def code_code_eval(python_code: str) -> str:
34
+ try:
35
+ result = PythonInterpreter(
36
+ {},
37
+ [
38
+ "os",
39
+ "math",
40
+ "random",
41
+ "datetime",
42
+ "time",
43
+ "string",
44
+ "collections",
45
+ "itertools",
46
+ "functools",
47
+ "typing",
48
+ "enum",
49
+ "json",
50
+ "ast",
51
+ ],
52
+ verbose=True,
53
+ ).execute(python_code)
54
+ return result
55
+ except Exception:
56
+ raise
@@ -0,0 +1,140 @@
1
+ import importlib
2
+ import json
3
+ from typing import Any
4
+
5
+ from flock.core.logging.trace_and_logged import traced_and_logged
6
+
7
+
8
+ @traced_and_logged
9
+ def file_get_anything_as_markdown(url_or_file_path: str):
10
+ if importlib.util.find_spec("docling") is not None:
11
+ from docling.document_converter import DocumentConverter
12
+
13
+ try:
14
+ converter = DocumentConverter()
15
+ result = converter.convert(url_or_file_path)
16
+ markdown = result.document.export_to_markdown()
17
+ return markdown
18
+ except Exception:
19
+ raise
20
+ else:
21
+ raise ImportError(
22
+ "Optional tool dependencies not installed. Install with 'pip install flock-core[file-tools]'."
23
+ )
24
+
25
+
26
+ @traced_and_logged
27
+ def file_save_to_file(content: str, filename: str):
28
+ try:
29
+ with open(filename, "w") as f:
30
+ f.write(content)
31
+ except Exception:
32
+ raise
33
+
34
+
35
+ @traced_and_logged
36
+ def file_read_from_file(filename: str) -> str:
37
+ with open(filename, encoding="utf-8") as file:
38
+ return file.read()
39
+
40
+
41
+ @traced_and_logged
42
+ def file_json_parse_safe(text: str) -> dict:
43
+ try:
44
+ result = json.loads(text)
45
+ return result
46
+ except Exception:
47
+ return {}
48
+
49
+
50
+ @traced_and_logged
51
+ def file_json_search(
52
+ json_file_path: str, search_query: str, case_sensitive: bool = False
53
+ ) -> list:
54
+ """Search a JSON file for objects containing the specified search query.
55
+
56
+ Args:
57
+ json_file_path (str): Path to the JSON file to search
58
+ search_query (str): Text to search for within the JSON objects
59
+ case_sensitive (bool, optional): Whether to perform a case-sensitive search. Defaults to False.
60
+
61
+ Returns:
62
+ list: List of JSON objects (as dicts) that contain the search query
63
+
64
+ Example:
65
+ >>> matching_tickets = file_json_search("tickets.json", "error 404")
66
+ >>> print(
67
+ ... f"Found {len(matching_tickets)} tickets mentioning '404 error'"
68
+ ... )
69
+ """
70
+ try:
71
+ # Read the JSON file
72
+ file_content = file_read_from_file(json_file_path)
73
+
74
+ # Parse the JSON content
75
+ json_data = file_json_parse_safe(file_content)
76
+
77
+ # Convert search query to lowercase if case-insensitive search
78
+ if not case_sensitive:
79
+ search_query = search_query.lower()
80
+
81
+ results = []
82
+
83
+ # Determine if the JSON root is an object or array
84
+ if isinstance(json_data, dict):
85
+ # Handle case where root is a dictionary object
86
+ for key, value in json_data.items():
87
+ if isinstance(value, list):
88
+ # If this key contains a list of objects, search within them
89
+ matching_items = _search_in_list(
90
+ value, search_query, case_sensitive
91
+ )
92
+ results.extend(matching_items)
93
+ elif _contains_text(value, search_query, case_sensitive):
94
+ # The entire object matches
95
+ results.append(json_data)
96
+ break
97
+ elif isinstance(json_data, list):
98
+ # Handle case where root is an array
99
+ matching_items = _search_in_list(
100
+ json_data, search_query, case_sensitive
101
+ )
102
+ results.extend(matching_items)
103
+
104
+ return results
105
+
106
+ except Exception as e:
107
+ return [{"error": f"Error searching JSON file: {e!s}"}]
108
+
109
+
110
+ def _search_in_list(
111
+ items: list, search_query: str, case_sensitive: bool
112
+ ) -> list:
113
+ """Helper function to search for text in a list of items."""
114
+ matching_items = []
115
+ for item in items:
116
+ if _contains_text(item, search_query, case_sensitive):
117
+ matching_items.append(item)
118
+ return matching_items
119
+
120
+
121
+ def _contains_text(obj: Any, search_query: str, case_sensitive: bool) -> bool:
122
+ """Recursively check if an object contains the search query in any of its string values."""
123
+ if isinstance(obj, str):
124
+ # For string values, check if they contain the search query
125
+ if case_sensitive:
126
+ return search_query in obj
127
+ else:
128
+ return search_query in obj.lower()
129
+ elif isinstance(obj, dict):
130
+ # For dictionaries, check each value
131
+ for value in obj.values():
132
+ if _contains_text(value, search_query, case_sensitive):
133
+ return True
134
+ elif isinstance(obj, list):
135
+ # For lists, check each item
136
+ for item in obj:
137
+ if _contains_text(item, search_query, case_sensitive):
138
+ return True
139
+ # For other types (numbers, booleans, None), return False
140
+ return False