fastworkflow 2.17.27__py3-none-any.whl → 2.17.29__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.
fastworkflow/__init__.py CHANGED
@@ -132,6 +132,12 @@ def init(env_vars: dict):
132
132
  global _env_vars, CommandContextModel, RoutingDefinition, RoutingRegistry, ModelPipelineRegistry
133
133
  _env_vars = env_vars
134
134
 
135
+ # Reconfigure log level from env_vars (dotenv files) if LOG_LEVEL is specified
136
+ # This allows LOG_LEVEL to be set in fastworkflow.env files, not just OS environment
137
+ if log_level := env_vars.get("LOG_LEVEL"):
138
+ from .utils.logging import reconfigure_log_level
139
+ reconfigure_log_level(log_level)
140
+
135
141
  # init before importing other modules so env vars are available
136
142
  from .command_context_model import CommandContextModel as CommandContextModelClass
137
143
  from .command_routing import RoutingDefinition as RoutingDefinitionClass
@@ -16,7 +16,7 @@ def get_import_block():
16
16
  f"from fastworkflow.train.generate_synthetic import generate_diverse_utterances\n"
17
17
  f"from fastworkflow.utils.context_utils import list_context_names\n"
18
18
  f"from typing import Any, Dict, Optional\n"
19
- f"from pydantic import BaseModel, Field\n"
19
+ f"from pydantic import BaseModel, Field, ConfigDict\n"
20
20
  )
21
21
 
22
22
  def create_function_command_file(function_info: FunctionInfo, output_dir: str, file_name: str = None, source_dir: str = None, overwrite: bool = False) -> str:
@@ -98,8 +98,10 @@ def create_function_command_file(function_info: FunctionInfo, output_dir: str, f
98
98
  call_param = ""
99
99
  call_arg = ""
100
100
 
101
- # Add Output class
102
- command_file_content += f" class Output(BaseModel):\n{output_fields}\n\n"
101
+ # Add Output class with arbitrary_types_allowed for non-Pydantic return types
102
+ command_file_content += f" class Output(BaseModel):\n"
103
+ command_file_content += f" model_config = ConfigDict(arbitrary_types_allowed=True)\n"
104
+ command_file_content += f"{output_fields}\n\n"
103
105
 
104
106
  # Add utterances
105
107
  command_file_content += f" plain_utterances = [\n{plain_utterances}\n ]\n\n"
@@ -326,8 +328,10 @@ def create_command_file(class_info, method_info, output_dir, file_name=None, is_
326
328
  # Add Input class if needed
327
329
  command_file_content += input_class
328
330
 
329
- # Add Output class
330
- command_file_content += f" class Output(BaseModel):\n{output_fields}\n\n"
331
+ # Add Output class with arbitrary_types_allowed for non-Pydantic return types
332
+ command_file_content += f" class Output(BaseModel):\n"
333
+ command_file_content += f" model_config = ConfigDict(arbitrary_types_allowed=True)\n"
334
+ command_file_content += f"{output_fields}\n\n"
331
335
 
332
336
  # Add utterances
333
337
  command_file_content += f" plain_utterances = [\n{plain_utterances}\n ]\n\n"
@@ -20,6 +20,7 @@ See docs/fastworkflow_fastapi_spec.md for complete specification.
20
20
 
21
21
  import asyncio
22
22
  import json
23
+ import logging
23
24
  import os
24
25
  import queue
25
26
  import time
@@ -106,6 +107,22 @@ class ProbeLoggingFilterMiddleware(BaseHTTPMiddleware):
106
107
  return response
107
108
 
108
109
 
110
+ class ProbeAccessLogFilter(logging.Filter):
111
+ """
112
+ Filter to suppress successful probe requests from uvicorn's access logger.
113
+
114
+ This prevents Kubernetes health check spam in access logs while preserving
115
+ access logs for all other endpoints. Failed probes (non-200) are still logged
116
+ via ProbeLoggingFilterMiddleware at WARNING level.
117
+ """
118
+
119
+ def filter(self, record: logging.LogRecord) -> bool:
120
+ message = record.getMessage()
121
+ return not any(
122
+ f'"{path}' in message and '" 200' in message for path in PROBE_PATHS
123
+ )
124
+
125
+
109
126
  # ============================================================================
110
127
  # Readiness State Tracking
111
128
  # ============================================================================
@@ -229,8 +246,6 @@ async def get_session_and_ensure_runtime(
229
246
  @asynccontextmanager
230
247
  async def lifespan(_app: FastAPI):
231
248
  """Startup and shutdown hooks"""
232
- logger.info("FastWorkflow FastAPI service starting...")
233
- logger.info(f"Startup with CLI params: workflow_path={ARGS.workflow_path}, env_file_path={ARGS.env_file_path}, passwords_file_path={ARGS.passwords_file_path}")
234
249
 
235
250
  def initialize_fastworkflow_on_startup() -> None:
236
251
  env_vars: dict[str, str] = {}
@@ -304,6 +319,9 @@ async def lifespan(_app: FastAPI):
304
319
 
305
320
  try:
306
321
  initialize_fastworkflow_on_startup()
322
+ # Log startup info AFTER init() so log level from env file is respected
323
+ logger.info("FastWorkflow FastAPI service starting...")
324
+ logger.info(f"Startup with CLI params: workflow_path={ARGS.workflow_path}, env_file_path={ARGS.env_file_path}, passwords_file_path={ARGS.passwords_file_path}")
307
325
  # Mark application as ready to accept traffic
308
326
  readiness_state.set_ready(True)
309
327
  logger.info("Application ready to accept traffic")
@@ -1485,7 +1503,21 @@ def main():
1485
1503
  """Entry point for the FastAPI MCP server."""
1486
1504
  host = ARGS.host if hasattr(ARGS, 'host') else "0.0.0.0"
1487
1505
  port = ARGS.port if hasattr(ARGS, 'port') else 8000
1488
- uvicorn.run(app, host=host, port=port)
1506
+
1507
+ # Read LOG_LEVEL from env file to configure uvicorn's logger
1508
+ # (env file isn't loaded until lifespan, but uvicorn needs log_level at startup)
1509
+ log_level = "info" # uvicorn default
1510
+ if hasattr(ARGS, 'env_file_path') and ARGS.env_file_path:
1511
+ env_vars = dotenv_values(ARGS.env_file_path)
1512
+ if "LOG_LEVEL" in env_vars:
1513
+ log_level = env_vars["LOG_LEVEL"].lower()
1514
+
1515
+ # Add filter to suppress successful probe requests from uvicorn's access logger
1516
+ # This preserves access logs for other endpoints while eliminating probe spam
1517
+ # Probe failures (non-200) are still logged via ProbeLoggingFilterMiddleware at WARNING level
1518
+ logging.getLogger("uvicorn.access").addFilter(ProbeAccessLogFilter())
1519
+
1520
+ uvicorn.run(app, host=host, port=port, log_level=log_level)
1489
1521
 
1490
1522
  if __name__ == "__main__":
1491
1523
  main()
@@ -113,6 +113,48 @@ logging.getLogger("speedict").setLevel(logging.WARNING)
113
113
  logging.getLogger("filelock").setLevel(logging.WARNING)
114
114
  logging.getLogger("datasets").setLevel(logging.WARNING)
115
115
 
116
+
117
+ def reconfigure_log_level(log_level_str: str) -> None:
118
+ """Reconfigure the fastWorkflow logger's level after initialization.
119
+
120
+ This allows LOG_LEVEL to be set via dotenv files loaded after module import.
121
+
122
+ Args:
123
+ log_level_str: One of DEBUG, INFO, WARNING, ERROR, CRITICAL
124
+ """
125
+ global LOG_LEVEL
126
+
127
+ level_map = {
128
+ "DEBUG": logging.DEBUG,
129
+ "INFO": logging.INFO,
130
+ "WARNING": logging.WARNING,
131
+ "ERROR": logging.ERROR,
132
+ "CRITICAL": logging.CRITICAL,
133
+ }
134
+
135
+ log_level_str_upper = log_level_str.upper()
136
+ if log_level_str_upper not in level_map:
137
+ logger.warning(
138
+ f"Invalid LOG_LEVEL '{log_level_str}', must be one of {list(level_map.keys())}. Keeping current level."
139
+ )
140
+ return
141
+
142
+ new_level = level_map[log_level_str_upper]
143
+
144
+ # Only reconfigure if the level is actually different
145
+ if LOG_LEVEL == new_level:
146
+ return
147
+
148
+ LOG_LEVEL = new_level
149
+ logger.setLevel(LOG_LEVEL)
150
+
151
+ # Update all handlers
152
+ for handler in logger.handlers:
153
+ handler.setLevel(LOG_LEVEL)
154
+
155
+ logger.info(f"Log level reconfigured to {log_level_str_upper}")
156
+
157
+
116
158
  # some testing code
117
159
  if __name__ == "__main__":
118
160
  logger.debug("debug message")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastworkflow
3
- Version: 2.17.27
3
+ Version: 2.17.29
4
4
  Summary: A framework for rapidly building large-scale, deterministic, interactive workflows with a fault-tolerant, conversational UX
5
5
  License: Apache-2.0
6
6
  Keywords: fastworkflow,ai,workflow,llm,openai
@@ -133,6 +133,9 @@ While [DSPy](https://dspy.ai) ([Why DSPy](https://x.com/lateinteraction/status/1
133
133
  - [Adding context hierarchies with context_inheritance_model.json](#adding-context-hierarchies-with-context_inheritance_modeljson)
134
134
  - [Using DSPy for Response Generation](#using-dspy-for-response-generation)
135
135
  - [Using Startup Commands and Actions](#using-startup-commands-and-actions)
136
+ - [Running FastWorkflow as a FastAPI Service](#running-fastworkflow-as-a-fastapi-service)
137
+ - [Kubernetes Liveness and Readiness Probes](#kubernetes-liveness-and-readiness-probes)
138
+ - [Using LiteLLM Proxy](#using-litellm-proxy)
136
139
  - [Rapidly Building Workflows with the Build Tool](#rapidly-building-workflows-with-the-build-tool)
137
140
  - [Environment Variables Reference](#environment-variables-reference)
138
141
  - [Environment Variables](#environment-variables)
@@ -582,6 +585,110 @@ For workflows with complex initialization requirements, creating a dedicated sta
582
585
 
583
586
  ---
584
587
 
588
+ ### Running FastWorkflow as a FastAPI Service
589
+
590
+ For production deployments and integrations, fastWorkflow provides a FastAPI-based HTTP service via the `run_fastapi_mcp` module. This exposes your workflow as REST endpoints with JWT authentication, SSE streaming, and MCP (Model Context Protocol) support.
591
+
592
+ ```sh
593
+ # Run the FastAPI service
594
+ python -m fastworkflow.run_fastapi_mcp \
595
+ --workflow_path ./my_workflow \
596
+ --env_file_path ./fastworkflow.env \
597
+ --passwords_file_path ./fastworkflow.passwords.env \
598
+ --port 8000
599
+ ```
600
+
601
+ The service provides endpoints for:
602
+ - `/initialize` - Create a new session and obtain JWT tokens
603
+ - `/invoke_agent` - Submit natural language queries to the agent
604
+ - `/invoke_agent_stream` - Stream responses via SSE or NDJSON
605
+ - `/perform_action` - Execute workflow actions directly
606
+ - `/conversations` - Manage conversation history
607
+
608
+ #### Kubernetes Liveness and Readiness Probes
609
+
610
+ When deploying fastWorkflow in Kubernetes, the service provides dedicated probe endpoints for health monitoring:
611
+
612
+ **Liveness Probe (`/probes/healthz`)**
613
+
614
+ Determines whether the container is still running. If this probe fails, Kubernetes will restart the container.
615
+
616
+ ```sh
617
+ curl http://localhost:8000/probes/healthz
618
+ # Response: {"status": "alive"}
619
+ ```
620
+
621
+ **Readiness Probe (`/probes/readyz`)**
622
+
623
+ Checks whether the container is ready to accept traffic. Kubernetes only routes traffic to containers that pass this check.
624
+
625
+ ```sh
626
+ curl http://localhost:8000/probes/readyz
627
+ # Response (ready): {"status": "ready", "checks": {"ready": true, "fastworkflow_initialized": true, "workflow_path_valid": true}}
628
+ # Response (not ready): {"status": "not_ready", "checks": {"ready": false, ...}}
629
+ ```
630
+
631
+ The readiness probe returns:
632
+ - `200 OK` when the application is ready to serve traffic
633
+ - `503 Service Unavailable` when not ready (e.g., during startup)
634
+
635
+ **Example Kubernetes Configuration**
636
+
637
+ ```yaml
638
+ apiVersion: apps/v1
639
+ kind: Deployment
640
+ spec:
641
+ template:
642
+ spec:
643
+ containers:
644
+ - name: fastworkflow
645
+ livenessProbe:
646
+ httpGet:
647
+ path: /probes/healthz
648
+ port: 8000
649
+ initialDelaySeconds: 10
650
+ periodSeconds: 10
651
+ failureThreshold: 5
652
+ timeoutSeconds: 3
653
+ readinessProbe:
654
+ httpGet:
655
+ path: /probes/readyz
656
+ port: 8000
657
+ initialDelaySeconds: 5
658
+ periodSeconds: 5
659
+ failureThreshold: 3
660
+ timeoutSeconds: 3
661
+ ```
662
+
663
+ > [!note]
664
+ > Probe endpoints do not require authentication and are excluded from request logging when returning 200 status to avoid excessive log noise from frequent Kubernetes health checks.
665
+
666
+ #### Using LiteLLM Proxy
667
+
668
+ FastWorkflow supports routing LLM calls through a [LiteLLM Proxy](https://docs.litellm.ai/docs/simple_proxy) server. This is useful when you want to:
669
+ - Centralize API key management
670
+ - Use a unified endpoint for multiple LLM providers
671
+ - Route requests through a corporate proxy with custom configurations
672
+
673
+ To use LiteLLM Proxy, set your model strings to use the `litellm_proxy/` prefix and configure the proxy URL:
674
+
675
+ ```
676
+ # In fastworkflow.env - use the litellm_proxy/ prefix for model names
677
+ LLM_AGENT=litellm_proxy/bedrock_mistral_large_2407
678
+ LLM_PARAM_EXTRACTION=litellm_proxy/bedrock_mistral_large_2407
679
+ LITELLM_PROXY_API_BASE=http://127.0.0.1:4000
680
+
681
+ # In fastworkflow.passwords.env - shared key for proxy authentication
682
+ LITELLM_PROXY_API_KEY=your-proxy-api-key
683
+ ```
684
+
685
+ The model name after `litellm_proxy/` (e.g., `bedrock_mistral_large_2407`) is passed to your proxy server, which routes it to the actual provider based on its configuration.
686
+
687
+ > [!note]
688
+ > When using `litellm_proxy/` models, the per-role API keys (`LITELLM_API_KEY_*`) are ignored. All proxied calls use the shared `LITELLM_PROXY_API_KEY` instead. You can mix proxied and direct models - only models with the `litellm_proxy/` prefix are routed through the proxy.
689
+
690
+ ---
691
+
585
692
  ## Rapidly Building Workflows with the Build Tool
586
693
 
587
694
  After understanding the manual process, you can use the `fastworkflow build` command to automate everything. It introspects your code and generates all the necessary files.
@@ -633,30 +740,6 @@ This single command will generate the `greet.py` command, `get_properties` and `
633
740
  > [!tip]
634
741
  > The example workflows are configured to use Mistral's models by default. You can get a free API key from [Mistral AI](https://mistral.ai) that works with the `mistral-small-latest` model.
635
742
 
636
- ### Using LiteLLM Proxy
637
-
638
- FastWorkflow supports routing LLM calls through a [LiteLLM Proxy](https://docs.litellm.ai/docs/simple_proxy) server. This is useful when you want to:
639
- - Centralize API key management
640
- - Use a unified endpoint for multiple LLM providers
641
- - Route requests through a corporate proxy with custom configurations
642
-
643
- To use LiteLLM Proxy, set your model strings to use the `litellm_proxy/` prefix and configure the proxy URL:
644
-
645
- ```
646
- # In fastworkflow.env - use the litellm_proxy/ prefix for model names
647
- LLM_AGENT=litellm_proxy/bedrock_mistral_large_2407
648
- LLM_PARAM_EXTRACTION=litellm_proxy/bedrock_mistral_large_2407
649
- LITELLM_PROXY_API_BASE=http://127.0.0.1:4000
650
-
651
- # In fastworkflow.passwords.env - shared key for proxy authentication
652
- LITELLM_PROXY_API_KEY=your-proxy-api-key
653
- ```
654
-
655
- The model name after `litellm_proxy/` (e.g., `bedrock_mistral_large_2407`) is passed to your proxy server, which routes it to the actual provider based on its configuration.
656
-
657
- > [!note]
658
- > When using `litellm_proxy/` models, the per-role API keys (`LITELLM_API_KEY_*`) are ignored. All proxied calls use the shared `LITELLM_PROXY_API_KEY` instead. You can mix proxied and direct models - only models with the `litellm_proxy/` prefix are routed through the proxy.
659
-
660
743
  ---
661
744
 
662
745
  ## Troubleshooting / FAQ
@@ -1,5 +1,5 @@
1
1
  fastworkflow/.DS_Store,sha256=CTvh7SVnPHlYsgd1jwLq9digT-k8QV6JS7JgXEw0OVo,8196
2
- fastworkflow/__init__.py,sha256=wrifGmkwLnHs6BupEliX20cDuV7WkQEKjNspunkzBlc,7604
2
+ fastworkflow/__init__.py,sha256=SiOTpsqqyHkg4XTeh9jveBPEn93rKdQG3xLTnBjskfU,7922
3
3
  fastworkflow/_commands/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  fastworkflow/_workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  fastworkflow/_workflows/command_metadata_extraction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -20,7 +20,7 @@ fastworkflow/build/class_analysis_structures.py,sha256=UWOKcs9pCiNuXc64hNywkTJq5
20
20
  fastworkflow/build/cli_specification.md,sha256=zAVG6wv7AzSotimAQlQmuq6y6ZumhdtftUBcKw3NdA0,3742
21
21
  fastworkflow/build/command_dependency_resolver.py,sha256=nNE7nANeDPXLvBlKkIS-8XVkNbg5dPVXB4lJMMANju8,3211
22
22
  fastworkflow/build/command_file_generator.py,sha256=i9ZcQLFUr-m1pxK1Vo79ons3yBzniuytx5vvY-0QfZ8,19630
23
- fastworkflow/build/command_file_template.py,sha256=U1t36YVtDUZVgBuXYsCw8ovK1ZQZkFhWYqNHvoI3hwk,18948
23
+ fastworkflow/build/command_file_template.py,sha256=MmKFnj81SDiNP8h2B4Pec_15WLWYmkR2radVVqfl_Go,19336
24
24
  fastworkflow/build/command_import_utils.py,sha256=nwyiurA9HDTLig-e9crBYVsVjkj4qfnLl8CqHUgs9XM,2127
25
25
  fastworkflow/build/command_stub_generator.py,sha256=KFOkAZfHeqyDlv59A3PfbuLn7jPXxXp-6MbjWO25LqE,13989
26
26
  fastworkflow/build/context_folder_generator.py,sha256=VpKoz3KYKGzCEFPqdVSwGLXLnrqN4MBU7TusOAhzfr0,5254
@@ -148,7 +148,7 @@ fastworkflow/run/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
148
148
  fastworkflow/run/__main__.py,sha256=kHgLI5kQ__4ITNFw7QJdv5u8nmmxbCyLsaiSde6Hnjc,12199
149
149
  fastworkflow/run_fastapi_mcp/README.md,sha256=dAmG2KF-9mqSjyIPSA9vhUit-DjsDH6WJUDCkQ3C1is,11943
150
150
  fastworkflow/run_fastapi_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
- fastworkflow/run_fastapi_mcp/__main__.py,sha256=vPdg7vEqxBvMDAAErk0MU921z9jXIRNqSuAPVGbBqKE,60540
151
+ fastworkflow/run_fastapi_mcp/__main__.py,sha256=OPd-BERua8XXuJ3r5uv8kdsVgdQ5qCGO9ezhW0n7Utw,61991
152
152
  fastworkflow/run_fastapi_mcp/conversation_store.py,sha256=2qnNLO_RVHznbIzTjpdff7szsrGyr1FVt1spcKvkrKk,13534
153
153
  fastworkflow/run_fastapi_mcp/jwt_manager.py,sha256=XHImakUgetCHRHwyacsWUtv0dhlrZtFF6vdastO6XEc,12507
154
154
  fastworkflow/run_fastapi_mcp/mcp_specific.py,sha256=RdOPcPn68KlxNSM9Vb2yeYEDNGoNTcKZq-AC0cd86cw,4506
@@ -167,7 +167,7 @@ fastworkflow/utils/dspy_utils.py,sha256=eFpU6jggaE9SGXO88Imxye6Q_EYsU0aymuFCGOsw
167
167
  fastworkflow/utils/env.py,sha256=2E9sev6kWEHP0jx1gs1Kv2HJAjr_mb8nyIPzWpRBU08,787
168
168
  fastworkflow/utils/fuzzy_match.py,sha256=9NRvgrhHezslGQdquFeWXxc2oE1eNYz4NFMEtsSeXMw,2521
169
169
  fastworkflow/utils/generate_param_examples.py,sha256=K0x1Zwe82xqhKA15AYTodWg7mquXsobXtqtZT-B5QAE,25581
170
- fastworkflow/utils/logging.py,sha256=CsPlhqtR2_HpWNk4iYVKSRtu_xeij6SQKy48xlnKEmI,4116
170
+ fastworkflow/utils/logging.py,sha256=Wj0kj6Cfdh1Ftig0NnVWJl-YxB7lxUEj1T_AcJPuEiQ,5304
171
171
  fastworkflow/utils/parameterize_func_decorator.py,sha256=V6YJnishWRCdwiBQW6P17hmGGrga0Empk-AN5Gm7iMk,633
172
172
  fastworkflow/utils/pydantic_model_2_dspy_signature_class.py,sha256=w1pvl8rJq48ulFwaAtBgfXYn_SBIDBgq1aLMUg1zJn8,12875
173
173
  fastworkflow/utils/python_utils.py,sha256=KMxktfIVOre7qkLhd80Ig39g313EMx_I_oHSa6sC5wI,8512
@@ -177,8 +177,8 @@ fastworkflow/utils/startup_progress.py,sha256=9icSdnpFAxzIq0sUliGpNaH0Efvrt5lDtG
177
177
  fastworkflow/workflow.py,sha256=37gn7e3ct-gdGw43zS6Ab_ADoJJBO4eJW2PywfUpjEg,18825
178
178
  fastworkflow/workflow_agent.py,sha256=jCvMyz5mLr8UX5QN1ssWebs4f24XhirjGkoJpsS-qZ0,19202
179
179
  fastworkflow/workflow_inheritance_model.py,sha256=Pp-qSrQISgPfPjJVUfW84pc7HLmL2evuq0UVIYR51K0,7974
180
- fastworkflow-2.17.27.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
181
- fastworkflow-2.17.27.dist-info/METADATA,sha256=DswdUGq2rnGkYoe_lGjUqtJYmm4IlUyjU3zpVqU-CmY,33130
182
- fastworkflow-2.17.27.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
183
- fastworkflow-2.17.27.dist-info/entry_points.txt,sha256=m8HqoPzCyaZLAx-V5X8MJgw3Lx3GiPDlxNEZ7K-Gb-U,54
184
- fastworkflow-2.17.27.dist-info/RECORD,,
180
+ fastworkflow-2.17.29.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
181
+ fastworkflow-2.17.29.dist-info/METADATA,sha256=03WQ1AuapBVYc1pRY3B29jHZ4yqMFI8B0zR5ct-YSBQ,36038
182
+ fastworkflow-2.17.29.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
183
+ fastworkflow-2.17.29.dist-info/entry_points.txt,sha256=m8HqoPzCyaZLAx-V5X8MJgw3Lx3GiPDlxNEZ7K-Gb-U,54
184
+ fastworkflow-2.17.29.dist-info/RECORD,,