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.
- flock/__init__.py +45 -3
- flock/core/flock.py +105 -61
- flock/core/flock_registry.py +45 -38
- flock/core/util/spliter.py +4 -0
- flock/evaluators/__init__.py +1 -0
- flock/evaluators/declarative/__init__.py +1 -0
- flock/modules/__init__.py +1 -0
- flock/modules/assertion/__init__.py +1 -0
- flock/modules/callback/__init__.py +1 -0
- flock/modules/mem0/__init__.py +1 -0
- flock/modules/mem0/mem0_module.py +63 -0
- flock/modules/mem0graph/__init__.py +1 -0
- flock/modules/mem0graph/mem0_graph_module.py +63 -0
- flock/modules/memory/__init__.py +1 -0
- flock/modules/output/__init__.py +1 -0
- flock/modules/performance/__init__.py +1 -0
- flock/tools/__init__.py +188 -0
- flock/{core/tools → tools}/azure_tools.py +284 -0
- flock/tools/code_tools.py +56 -0
- flock/tools/file_tools.py +140 -0
- flock/{core/tools/dev_tools/github.py → tools/github_tools.py} +3 -3
- flock/{core/tools → tools}/markdown_tools.py +14 -4
- flock/tools/system_tools.py +9 -0
- flock/{core/tools/llm_tools.py → tools/text_tools.py} +47 -25
- flock/tools/web_tools.py +90 -0
- flock/{core/tools → tools}/zendesk_tools.py +6 -6
- flock/webapp/app/api/execution.py +130 -30
- flock/webapp/app/chat.py +303 -16
- flock/webapp/app/config.py +15 -1
- flock/webapp/app/dependencies.py +22 -0
- flock/webapp/app/main.py +509 -18
- flock/webapp/app/services/flock_service.py +38 -13
- flock/webapp/app/services/sharing_models.py +43 -0
- flock/webapp/app/services/sharing_store.py +156 -0
- flock/webapp/static/css/chat.css +57 -0
- flock/webapp/templates/chat.html +29 -4
- flock/webapp/templates/partials/_chat_messages.html +1 -1
- flock/webapp/templates/partials/_chat_settings_form.html +22 -0
- flock/webapp/templates/partials/_execution_form.html +28 -1
- flock/webapp/templates/partials/_share_chat_link_snippet.html +11 -0
- flock/webapp/templates/partials/_share_link_snippet.html +35 -0
- flock/webapp/templates/shared_run_page.html +116 -0
- flock/workflow/activities.py +1 -0
- {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/METADATA +27 -14
- {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/RECORD +48 -28
- flock/core/tools/basic_tools.py +0 -317
- flock/modules/zep/zep_module.py +0 -187
- {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/WHEEL +0 -0
- {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/entry_points.txt +0 -0
- {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b49.dist-info}/licenses/LICENSE +0 -0
flock/tools/__init__.py
ADDED
|
@@ -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
|