flock-core 0.4.0b25__py3-none-any.whl → 0.4.0b27__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 +10 -14
- flock/cli/load_release_notes.py +1 -4
- flock/core/context/context.py +10 -1
- flock/core/execution/temporal_executor.py +142 -25
- flock/core/flock.py +56 -6
- flock/core/flock_agent.py +146 -147
- flock/core/flock_factory.py +3 -0
- flock/core/util/cli_helper.py +8 -5
- flock/evaluators/declarative/declarative_evaluator.py +8 -4
- flock/modules/performance/metrics_module.py +3 -0
- flock/workflow/agent_execution_activity.py +228 -0
- flock/workflow/flock_workflow.py +225 -0
- flock/workflow/temporal_config.py +96 -0
- flock/workflow/temporal_setup.py +29 -7
- {flock_core-0.4.0b25.dist-info → flock_core-0.4.0b27.dist-info}/METADATA +31 -5
- {flock_core-0.4.0b25.dist-info → flock_core-0.4.0b27.dist-info}/RECORD +19 -17
- flock/workflow/workflow.py +0 -58
- {flock_core-0.4.0b25.dist-info → flock_core-0.4.0b27.dist-info}/WHEEL +0 -0
- {flock_core-0.4.0b25.dist-info → flock_core-0.4.0b27.dist-info}/entry_points.txt +0 -0
- {flock_core-0.4.0b25.dist-info → flock_core-0.4.0b27.dist-info}/licenses/LICENSE +0 -0
flock/__init__.py
CHANGED
|
@@ -1,35 +1,31 @@
|
|
|
1
1
|
"""Flock package initialization."""
|
|
2
2
|
|
|
3
|
-
from rich.panel import Panel
|
|
4
|
-
|
|
5
|
-
from flock.cli.config import init_config_file, load_config_file
|
|
6
|
-
from flock.cli.constants import (
|
|
7
|
-
CLI_CFG_FILE,
|
|
8
|
-
CLI_EXIT,
|
|
9
|
-
CLI_NOTES,
|
|
10
|
-
CLI_REGISTRY_MANAGEMENT,
|
|
11
|
-
CLI_THEME_BUILDER,
|
|
12
|
-
)
|
|
13
|
-
from flock.cli.load_release_notes import load_release_notes
|
|
14
|
-
from flock.cli.settings import settings_editor
|
|
15
|
-
from flock.core.logging.formatters.theme_builder import theme_builder
|
|
16
|
-
|
|
17
3
|
|
|
18
4
|
def main():
|
|
19
5
|
"""Main function."""
|
|
20
6
|
import questionary
|
|
21
7
|
from rich.console import Console
|
|
8
|
+
from rich.panel import Panel
|
|
22
9
|
|
|
10
|
+
from flock.cli.config import init_config_file, load_config_file
|
|
23
11
|
from flock.cli.constants import (
|
|
12
|
+
CLI_CFG_FILE,
|
|
24
13
|
CLI_CREATE_AGENT,
|
|
25
14
|
CLI_CREATE_FLOCK,
|
|
15
|
+
CLI_EXIT,
|
|
26
16
|
CLI_LOAD_AGENT,
|
|
27
17
|
CLI_LOAD_EXAMPLE,
|
|
28
18
|
CLI_LOAD_FLOCK,
|
|
19
|
+
CLI_NOTES,
|
|
20
|
+
CLI_REGISTRY_MANAGEMENT,
|
|
29
21
|
CLI_SETTINGS,
|
|
30
22
|
CLI_START_WEB_SERVER,
|
|
23
|
+
CLI_THEME_BUILDER,
|
|
31
24
|
)
|
|
32
25
|
from flock.cli.load_flock import load_flock
|
|
26
|
+
from flock.cli.load_release_notes import load_release_notes
|
|
27
|
+
from flock.cli.settings import settings_editor
|
|
28
|
+
from flock.core.logging.formatters.theme_builder import theme_builder
|
|
33
29
|
from flock.core.util.cli_helper import init_console
|
|
34
30
|
|
|
35
31
|
console = Console()
|
flock/cli/load_release_notes.py
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
-
from flock.core.util.cli_helper import display_hummingbird
|
|
4
|
-
|
|
5
3
|
|
|
6
4
|
def load_release_notes():
|
|
7
5
|
"""Load release notes."""
|
|
8
6
|
from rich.console import Console
|
|
9
7
|
from rich.markdown import Markdown
|
|
10
8
|
|
|
11
|
-
from flock.core.util.cli_helper import init_console
|
|
9
|
+
from flock.core.util.cli_helper import display_hummingbird, init_console
|
|
12
10
|
|
|
13
11
|
console = Console()
|
|
14
12
|
file_path = Path(__file__).parent / "assets" / "release_notes.md"
|
|
@@ -19,5 +17,4 @@ def load_release_notes():
|
|
|
19
17
|
with open(file_path) as file:
|
|
20
18
|
release_notes = file.read()
|
|
21
19
|
|
|
22
|
-
|
|
23
20
|
console.print(Markdown(release_notes))
|
flock/core/context/context.py
CHANGED
|
@@ -20,7 +20,7 @@ class AgentRunRecord(BaseModel):
|
|
|
20
20
|
data: dict[str, Any] = Field(default_factory=dict)
|
|
21
21
|
timestamp: str = Field(default="")
|
|
22
22
|
hand_off: dict | None = Field(default_factory=dict)
|
|
23
|
-
called_from: str = Field(default=
|
|
23
|
+
called_from: str | None = Field(default=None)
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class AgentDefinition(BaseModel):
|
|
@@ -132,6 +132,15 @@ class FlockContext(Serializable, BaseModel):
|
|
|
132
132
|
def get_agent_definition(self, agent_name: str) -> AgentDefinition | None:
|
|
133
133
|
return self.agent_definitions.get(agent_name)
|
|
134
134
|
|
|
135
|
+
def get_last_agent_name(self) -> str | None:
|
|
136
|
+
"""Returns the name of the agent from the most recent history record."""
|
|
137
|
+
if not self.history:
|
|
138
|
+
return None
|
|
139
|
+
last_record = self.history[-1]
|
|
140
|
+
# The 'called_from' field in the *next* record is the previous agent.
|
|
141
|
+
# However, to get the name of the *last executed agent*, we look at the 'agent' field.
|
|
142
|
+
return last_record.agent
|
|
143
|
+
|
|
135
144
|
def add_agent_definition(
|
|
136
145
|
self, agent_type: type, agent_name: str, agent_data: Any
|
|
137
146
|
) -> None:
|
|
@@ -1,49 +1,166 @@
|
|
|
1
1
|
# src/your_package/core/execution/temporal_executor.py
|
|
2
2
|
|
|
3
|
+
import asyncio # Import asyncio
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
|
+
|
|
6
|
+
from temporalio.worker import Worker # Import Worker
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from flock.core.flock import Flock # Import Flock for type hinting
|
|
10
|
+
|
|
3
11
|
from flock.core.context.context import FlockContext
|
|
4
12
|
from flock.core.context.context_vars import FLOCK_RUN_ID
|
|
5
13
|
from flock.core.logging.logging import get_logger
|
|
6
|
-
from flock.workflow.
|
|
7
|
-
|
|
14
|
+
from flock.workflow.agent_execution_activity import (
|
|
15
|
+
determine_next_agent,
|
|
16
|
+
execute_single_agent,
|
|
17
|
+
)
|
|
18
|
+
from flock.workflow.temporal_config import (
|
|
19
|
+
TemporalRetryPolicyConfig,
|
|
20
|
+
TemporalWorkflowConfig,
|
|
8
21
|
)
|
|
9
22
|
from flock.workflow.temporal_setup import create_temporal_client, setup_worker
|
|
10
|
-
from flock.workflow.workflow import FlockWorkflow # Your workflow class
|
|
11
23
|
|
|
12
24
|
logger = get_logger("flock")
|
|
13
25
|
|
|
14
26
|
|
|
15
27
|
async def run_temporal_workflow(
|
|
28
|
+
flock_instance: "Flock", # Accept Flock instance
|
|
16
29
|
context: FlockContext,
|
|
17
30
|
box_result: bool = True,
|
|
31
|
+
memo: dict[str, Any] | None = None, # Add memo argument
|
|
18
32
|
) -> dict:
|
|
19
33
|
"""Execute the agent workflow via Temporal for robust, distributed processing.
|
|
20
34
|
|
|
21
35
|
Args:
|
|
36
|
+
flock_instance: The Flock instance.
|
|
22
37
|
context: The FlockContext instance with state and history.
|
|
23
38
|
box_result: If True, wraps the result in a Box for nicer display.
|
|
39
|
+
memo: Optional dictionary of metadata to attach to the Temporal workflow.
|
|
24
40
|
|
|
25
41
|
Returns:
|
|
26
42
|
A dictionary containing the workflow result.
|
|
27
43
|
"""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
try:
|
|
45
|
+
from flock.workflow.flock_workflow import (
|
|
46
|
+
FlockWorkflow, # Your workflow class
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Get workflow config from Flock instance or use defaults
|
|
50
|
+
wf_config = flock_instance.temporal_config or TemporalWorkflowConfig()
|
|
51
|
+
|
|
52
|
+
logger.debug("Creating Temporal client")
|
|
53
|
+
flock_client = await create_temporal_client()
|
|
54
|
+
|
|
55
|
+
# Determine if we need to manage an in-process worker
|
|
56
|
+
start_worker_locally = flock_instance.temporal_start_in_process_worker
|
|
57
|
+
|
|
58
|
+
# Setup worker instance
|
|
59
|
+
worker: Worker | None = None
|
|
60
|
+
worker_task: asyncio.Task | None = None
|
|
61
|
+
|
|
62
|
+
if start_worker_locally:
|
|
63
|
+
logger.info(
|
|
64
|
+
f"Setting up temporary in-process worker for task queue '{wf_config.task_queue}'"
|
|
65
|
+
)
|
|
66
|
+
worker = await setup_worker(
|
|
67
|
+
flock_client, # Pass the client
|
|
68
|
+
wf_config.task_queue, # Pass the task queue
|
|
69
|
+
FlockWorkflow,
|
|
70
|
+
[execute_single_agent, determine_next_agent],
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Run the worker in the background
|
|
74
|
+
worker_task = asyncio.create_task(worker.run())
|
|
75
|
+
logger.info("Temporal worker started in background.")
|
|
76
|
+
|
|
77
|
+
# Allow worker time to start polling (heuristic for local testing)
|
|
78
|
+
await asyncio.sleep(2)
|
|
79
|
+
else:
|
|
80
|
+
logger.info(
|
|
81
|
+
"Skipping in-process worker startup. Assuming dedicated workers are running."
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
workflow_id = context.get_variable(FLOCK_RUN_ID)
|
|
86
|
+
logger.info(
|
|
87
|
+
"Executing Temporal workflow",
|
|
88
|
+
workflow_id=workflow_id,
|
|
89
|
+
task_queue=wf_config.task_queue,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Prepare the single workflow argument dictionary
|
|
93
|
+
workflow_args_dict = {
|
|
94
|
+
"context_dict": context.model_dump(mode="json"),
|
|
95
|
+
"default_retry_config_dict": (
|
|
96
|
+
wf_config.default_activity_retry_policy.model_dump(
|
|
97
|
+
mode="json"
|
|
98
|
+
)
|
|
99
|
+
if wf_config.default_activity_retry_policy
|
|
100
|
+
else TemporalRetryPolicyConfig().model_dump(mode="json")
|
|
101
|
+
),
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Start the workflow using start_workflow
|
|
105
|
+
handle = await flock_client.start_workflow(
|
|
106
|
+
FlockWorkflow.run,
|
|
107
|
+
# Pass the single dictionary as the only element in the args list
|
|
108
|
+
args=[workflow_args_dict],
|
|
109
|
+
id=workflow_id,
|
|
110
|
+
task_queue=wf_config.task_queue,
|
|
111
|
+
# Corrected timeout argument names
|
|
112
|
+
execution_timeout=wf_config.workflow_execution_timeout,
|
|
113
|
+
run_timeout=wf_config.workflow_run_timeout,
|
|
114
|
+
memo=memo or {}, # Pass memo if provided
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
logger.info(
|
|
118
|
+
"Workflow started, awaiting result...", workflow_id=handle.id
|
|
119
|
+
)
|
|
120
|
+
# Await the result from the handle
|
|
121
|
+
result = await handle.result()
|
|
122
|
+
logger.info("Workflow result received.")
|
|
123
|
+
|
|
124
|
+
agent_name = context.get_variable("FLOCK_CURRENT_AGENT")
|
|
125
|
+
logger.debug("Formatting Temporal result", agent=agent_name)
|
|
126
|
+
|
|
127
|
+
if box_result:
|
|
128
|
+
from box import Box
|
|
129
|
+
|
|
130
|
+
logger.debug("Boxing Temporal result")
|
|
131
|
+
return Box(result)
|
|
132
|
+
return result
|
|
133
|
+
except Exception as e:
|
|
134
|
+
logger.error(
|
|
135
|
+
"Error during Temporal workflow execution or result retrieval",
|
|
136
|
+
error=e,
|
|
137
|
+
)
|
|
138
|
+
raise e # Re-raise the exception after logging
|
|
139
|
+
finally:
|
|
140
|
+
# Ensure worker is shut down regardless of success or failure
|
|
141
|
+
if (
|
|
142
|
+
start_worker_locally
|
|
143
|
+
and worker
|
|
144
|
+
and worker_task
|
|
145
|
+
and not worker_task.done()
|
|
146
|
+
):
|
|
147
|
+
logger.info("Shutting down temporal worker...")
|
|
148
|
+
await worker.shutdown() # Await the shutdown coroutine
|
|
149
|
+
try:
|
|
150
|
+
await asyncio.wait_for(
|
|
151
|
+
worker_task, timeout=10.0
|
|
152
|
+
) # Wait for task to finish
|
|
153
|
+
logger.info("Temporal worker shut down gracefully.")
|
|
154
|
+
except asyncio.TimeoutError:
|
|
155
|
+
logger.warning(
|
|
156
|
+
"Temporal worker shutdown timed out. Cancelling task."
|
|
157
|
+
)
|
|
158
|
+
worker_task.cancel()
|
|
159
|
+
except Exception as shutdown_err:
|
|
160
|
+
logger.error(
|
|
161
|
+
f"Error during worker shutdown: {shutdown_err}",
|
|
162
|
+
exc_info=True,
|
|
163
|
+
)
|
|
164
|
+
except Exception as e:
|
|
165
|
+
logger.error("Error executing Temporal workflow", error=e)
|
|
166
|
+
raise e
|
flock/core/flock.py
CHANGED
|
@@ -17,7 +17,14 @@ from typing import (
|
|
|
17
17
|
|
|
18
18
|
# Third-party imports
|
|
19
19
|
from box import Box
|
|
20
|
-
from
|
|
20
|
+
from temporalio import workflow
|
|
21
|
+
|
|
22
|
+
with workflow.unsafe.imports_passed_through():
|
|
23
|
+
from datasets import Dataset
|
|
24
|
+
|
|
25
|
+
from flock.core.execution.local_executor import (
|
|
26
|
+
run_local_workflow,
|
|
27
|
+
)
|
|
21
28
|
from opentelemetry import trace
|
|
22
29
|
from opentelemetry.baggage import get_baggage, set_baggage
|
|
23
30
|
from pandas import DataFrame
|
|
@@ -27,12 +34,12 @@ from pydantic import BaseModel, Field
|
|
|
27
34
|
from flock.config import DEFAULT_MODEL, TELEMETRY
|
|
28
35
|
from flock.core.context.context import FlockContext
|
|
29
36
|
from flock.core.context.context_manager import initialize_context
|
|
30
|
-
from flock.core.execution.local_executor import run_local_workflow
|
|
31
37
|
from flock.core.execution.temporal_executor import run_temporal_workflow
|
|
32
38
|
from flock.core.flock_evaluator import FlockEvaluator
|
|
33
39
|
from flock.core.logging.logging import LOGGERS, get_logger, get_module_loggers
|
|
34
40
|
from flock.core.serialization.serializable import Serializable
|
|
35
41
|
from flock.core.util.cli_helper import init_console
|
|
42
|
+
from flock.workflow.temporal_config import TemporalWorkflowConfig
|
|
36
43
|
|
|
37
44
|
# Import FlockAgent using TYPE_CHECKING to avoid circular import at runtime
|
|
38
45
|
if TYPE_CHECKING:
|
|
@@ -59,9 +66,9 @@ FlockRegistry = get_registry() # Get the registry instance
|
|
|
59
66
|
# Define TypeVar for generic class methods like from_dict
|
|
60
67
|
T = TypeVar("T", bound="Flock")
|
|
61
68
|
|
|
62
|
-
from rich.traceback import install
|
|
69
|
+
# from rich.traceback import install
|
|
63
70
|
|
|
64
|
-
install(show_locals=True)
|
|
71
|
+
# install(show_locals=True)
|
|
65
72
|
|
|
66
73
|
|
|
67
74
|
class Flock(BaseModel, Serializable):
|
|
@@ -96,6 +103,16 @@ class Flock(BaseModel, Serializable):
|
|
|
96
103
|
default=True,
|
|
97
104
|
description="If True, show the Flock banner on console interactions.",
|
|
98
105
|
)
|
|
106
|
+
# --- Temporal Configuration (Optional) ---
|
|
107
|
+
temporal_config: TemporalWorkflowConfig | None = Field(
|
|
108
|
+
default=None,
|
|
109
|
+
description="Optional Temporal settings specific to the workflow execution for this Flock.",
|
|
110
|
+
)
|
|
111
|
+
# --- Temporal Dev/Test Setting ---
|
|
112
|
+
temporal_start_in_process_worker: bool = Field(
|
|
113
|
+
default=True,
|
|
114
|
+
description="If True (default) and enable_temporal=True, start a temporary in-process worker for development/testing convenience. Set to False when using dedicated workers.",
|
|
115
|
+
)
|
|
99
116
|
# Internal agent storage - not part of the Pydantic model for direct serialization
|
|
100
117
|
_agents: dict[str, FlockAgent]
|
|
101
118
|
_start_agent_name: str | None = None # For potential pre-configuration
|
|
@@ -116,6 +133,8 @@ class Flock(BaseModel, Serializable):
|
|
|
116
133
|
enable_temporal: bool = False,
|
|
117
134
|
enable_logging: bool | list[str] = False,
|
|
118
135
|
agents: list[FlockAgent] | None = None,
|
|
136
|
+
temporal_config: TemporalWorkflowConfig | None = None,
|
|
137
|
+
temporal_start_in_process_worker: bool = True,
|
|
119
138
|
**kwargs,
|
|
120
139
|
):
|
|
121
140
|
"""Initialize the Flock orchestrator."""
|
|
@@ -130,6 +149,8 @@ class Flock(BaseModel, Serializable):
|
|
|
130
149
|
enable_temporal=enable_temporal,
|
|
131
150
|
enable_logging=enable_logging,
|
|
132
151
|
show_flock_banner=show_flock_banner,
|
|
152
|
+
temporal_config=temporal_config,
|
|
153
|
+
temporal_start_in_process_worker=temporal_start_in_process_worker,
|
|
133
154
|
**kwargs,
|
|
134
155
|
)
|
|
135
156
|
|
|
@@ -305,6 +326,7 @@ class Flock(BaseModel, Serializable):
|
|
|
305
326
|
run_id: str = "",
|
|
306
327
|
box_result: bool = True,
|
|
307
328
|
agents: list[FlockAgent] | None = None,
|
|
329
|
+
memo: dict[str, Any] | None = None,
|
|
308
330
|
) -> Box | dict:
|
|
309
331
|
"""Entry point for running an agent system asynchronously."""
|
|
310
332
|
# Import here to allow forward reference resolution
|
|
@@ -342,7 +364,17 @@ class Flock(BaseModel, Serializable):
|
|
|
342
364
|
|
|
343
365
|
# Check if start_agent is in agents
|
|
344
366
|
if start_agent_name not in self._agents:
|
|
345
|
-
|
|
367
|
+
# Try loading from registry if not found locally yet
|
|
368
|
+
reg_agent = FlockRegistry.get_agent(start_agent_name)
|
|
369
|
+
if reg_agent:
|
|
370
|
+
self.add_agent(reg_agent)
|
|
371
|
+
logger.info(
|
|
372
|
+
f"Loaded start agent '{start_agent_name}' from registry."
|
|
373
|
+
)
|
|
374
|
+
else:
|
|
375
|
+
raise ValueError(
|
|
376
|
+
f"Start agent '{start_agent_name}' not found locally or in registry."
|
|
377
|
+
)
|
|
346
378
|
|
|
347
379
|
run_input = input if input is not None else self._start_input
|
|
348
380
|
effective_run_id = run_id or f"flockrun_{uuid.uuid4().hex[:8]}"
|
|
@@ -388,6 +420,15 @@ class Flock(BaseModel, Serializable):
|
|
|
388
420
|
agent_data=agent_dict_repr, # Pass the serialized dict
|
|
389
421
|
)
|
|
390
422
|
|
|
423
|
+
# Add temporal config to context if enabled
|
|
424
|
+
if self.enable_temporal and self.temporal_config:
|
|
425
|
+
# Store the workflow config dict for the executor/workflow to use
|
|
426
|
+
# Using a specific key to avoid potential clashes in state
|
|
427
|
+
run_context.set_variable(
|
|
428
|
+
"flock.temporal_workflow_config",
|
|
429
|
+
self.temporal_config.model_dump(mode="json"),
|
|
430
|
+
)
|
|
431
|
+
|
|
391
432
|
logger.info(
|
|
392
433
|
"Starting agent execution",
|
|
393
434
|
agent=start_agent_name,
|
|
@@ -400,8 +441,15 @@ class Flock(BaseModel, Serializable):
|
|
|
400
441
|
run_context, box_result=False
|
|
401
442
|
)
|
|
402
443
|
else:
|
|
444
|
+
# Pass the Flock instance itself to the executor
|
|
445
|
+
# so it can access the temporal_config directly if needed
|
|
446
|
+
# This avoids putting potentially large/complex config objects
|
|
447
|
+
# directly into the context state that gets passed around.
|
|
403
448
|
result = await run_temporal_workflow(
|
|
404
|
-
|
|
449
|
+
self, # Pass the Flock instance
|
|
450
|
+
run_context,
|
|
451
|
+
box_result=False,
|
|
452
|
+
memo=memo,
|
|
405
453
|
)
|
|
406
454
|
|
|
407
455
|
span.set_attribute("result.type", str(type(result)))
|
|
@@ -662,6 +710,7 @@ class Flock(BaseModel, Serializable):
|
|
|
662
710
|
# Import locally to prevent circular imports at module level if structure is complex
|
|
663
711
|
from flock.core.serialization.flock_serializer import FlockSerializer
|
|
664
712
|
|
|
713
|
+
# Assuming FlockSerializer handles the nested temporal_config serialization
|
|
665
714
|
return FlockSerializer.serialize(self, path_type=path_type)
|
|
666
715
|
|
|
667
716
|
@classmethod
|
|
@@ -670,6 +719,7 @@ class Flock(BaseModel, Serializable):
|
|
|
670
719
|
# Import locally
|
|
671
720
|
from flock.core.serialization.flock_serializer import FlockSerializer
|
|
672
721
|
|
|
722
|
+
# Assuming FlockSerializer handles the nested temporal_config deserialization
|
|
673
723
|
return FlockSerializer.deserialize(cls, data)
|
|
674
724
|
|
|
675
725
|
# --- Static Method Loader (Delegates to loader module) ---
|