levelapp 0.1.3__py3-none-any.whl → 0.1.5__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 levelapp might be problematic. Click here for more details.
- levelapp/aspects/loader.py +4 -4
- levelapp/config/api_config.yaml +156 -0
- levelapp/config/dashq_api.yaml +94 -0
- levelapp/config/endpoint_.py +325 -5
- levelapp/config/endpoints.yaml +47 -0
- levelapp/core/session.py +8 -0
- levelapp/endpoint/__init__.py +0 -0
- levelapp/endpoint/client.py +102 -0
- levelapp/endpoint/manager.py +114 -0
- levelapp/endpoint/parsers.py +120 -0
- levelapp/endpoint/schemas.py +38 -0
- levelapp/endpoint/tester.py +53 -0
- levelapp/endpoint/usage_example.py +39 -0
- levelapp/evaluator/evaluator.py +9 -1
- levelapp/repository/filesystem.py +203 -0
- levelapp/simulator/schemas.py +4 -4
- levelapp/simulator/simulator.py +57 -43
- levelapp/simulator/utils.py +52 -81
- levelapp/workflow/base.py +33 -2
- levelapp/workflow/config.py +6 -2
- levelapp/workflow/context.py +3 -1
- levelapp/workflow/runtime.py +3 -3
- {levelapp-0.1.3.dist-info → levelapp-0.1.5.dist-info}/METADATA +146 -31
- {levelapp-0.1.3.dist-info → levelapp-0.1.5.dist-info}/RECORD +26 -15
- {levelapp-0.1.3.dist-info → levelapp-0.1.5.dist-info}/WHEEL +0 -0
- {levelapp-0.1.3.dist-info → levelapp-0.1.5.dist-info}/licenses/LICENSE +0 -0
levelapp/simulator/schemas.py
CHANGED
|
@@ -9,7 +9,7 @@ from uuid import UUID, uuid4
|
|
|
9
9
|
from datetime import datetime
|
|
10
10
|
|
|
11
11
|
from typing import Dict, Any, List
|
|
12
|
-
from pydantic import BaseModel, Field, computed_field
|
|
12
|
+
from pydantic import BaseModel, Field, computed_field
|
|
13
13
|
|
|
14
14
|
from levelapp.evaluator.evaluator import JudgeEvaluationResults
|
|
15
15
|
|
|
@@ -24,13 +24,12 @@ class InteractionLevel(str, Enum):
|
|
|
24
24
|
class Interaction(BaseModel):
|
|
25
25
|
"""Represents a single interaction within a conversation."""
|
|
26
26
|
id: UUID = Field(default_factory=uuid4, description="Interaction identifier")
|
|
27
|
+
user_message_path: str = Field(..., description="Path of the user message in the request payload")
|
|
27
28
|
user_message: str = Field(..., description="The user's query message")
|
|
28
|
-
# generated_reply: str = Field(..., description="The agent's reply message")
|
|
29
29
|
reference_reply: str = Field(..., description="The preset reference message")
|
|
30
30
|
interaction_type: InteractionLevel = Field(default=InteractionLevel.INITIAL, description="Type of interaction")
|
|
31
31
|
reference_metadata: Dict[str, Any] = Field(default_factory=dict, description="Expected metadata")
|
|
32
|
-
|
|
33
|
-
guardrail_flag: bool = Field(default=False, description="Flag for guardrail signaling")
|
|
32
|
+
guardrail_flag: Any = Field(default=False, description="Flag for guardrail signaling")
|
|
34
33
|
request_payload: Dict[str, Any] = Field(default_factory=dict, description="Additional request payload")
|
|
35
34
|
|
|
36
35
|
|
|
@@ -40,6 +39,7 @@ class ConversationScript(BaseModel):
|
|
|
40
39
|
interactions: List[Interaction] = Field(default_factory=list, description="List of interactions")
|
|
41
40
|
description: str = Field(default="no-description", description="A short description of the conversation")
|
|
42
41
|
details: Dict[str, str] = Field(default_factory=dict, description="Conversation details")
|
|
42
|
+
variable_request_schema: bool = Field(default=False, description="The payload schema changes for each request")
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
class ScriptsBatch(BaseModel):
|
levelapp/simulator/simulator.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
'simulators/service.py': Service layer to manage conversation simulation and evaluation.
|
|
3
3
|
"""
|
|
4
|
-
import json
|
|
5
4
|
import time
|
|
6
5
|
import asyncio
|
|
7
6
|
|
|
@@ -9,8 +8,12 @@ from datetime import datetime
|
|
|
9
8
|
from collections import defaultdict
|
|
10
9
|
from typing import Dict, Any, List
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
from levelapp.
|
|
11
|
+
|
|
12
|
+
from levelapp.core.base import BaseProcess, BaseEvaluator
|
|
13
|
+
from levelapp.endpoint.client import EndpointConfig
|
|
14
|
+
from levelapp.endpoint.manager import EndpointConfigManager
|
|
15
|
+
|
|
16
|
+
from levelapp.core.schemas import EvaluatorType
|
|
14
17
|
from levelapp.simulator.schemas import (
|
|
15
18
|
InteractionEvaluationResults,
|
|
16
19
|
ScriptsBatch,
|
|
@@ -18,13 +21,10 @@ from levelapp.simulator.schemas import (
|
|
|
18
21
|
SimulationResults
|
|
19
22
|
)
|
|
20
23
|
from levelapp.simulator.utils import (
|
|
21
|
-
extract_interaction_details,
|
|
22
|
-
async_interaction_request,
|
|
23
24
|
calculate_average_scores,
|
|
24
25
|
summarize_verdicts,
|
|
25
26
|
)
|
|
26
27
|
from levelapp.aspects import logger
|
|
27
|
-
from levelapp.core.schemas import EvaluatorType
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class ConversationSimulator(BaseProcess):
|
|
@@ -32,29 +32,26 @@ class ConversationSimulator(BaseProcess):
|
|
|
32
32
|
|
|
33
33
|
def __init__(
|
|
34
34
|
self,
|
|
35
|
-
|
|
35
|
+
endpoint_config: EndpointConfig | None = None,
|
|
36
36
|
evaluators: Dict[EvaluatorType, BaseEvaluator] | None = None,
|
|
37
37
|
providers: List[str] | None = None,
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
):
|
|
40
40
|
"""
|
|
41
41
|
Initialize the ConversationSimulator.
|
|
42
42
|
|
|
43
43
|
Args:
|
|
44
|
-
|
|
44
|
+
endpoint_config (EndpointConfig): Endpoint configuration.
|
|
45
45
|
evaluators (EvaluationService): Service for evaluating interactions.
|
|
46
46
|
endpoint_config (EndpointConfig): Configuration object for VLA.
|
|
47
47
|
"""
|
|
48
48
|
self._CLASS_NAME = self.__class__.__name__
|
|
49
49
|
|
|
50
|
-
self.
|
|
50
|
+
self.endpoint_config = endpoint_config
|
|
51
51
|
self.evaluators = evaluators
|
|
52
52
|
self.providers = providers
|
|
53
|
-
self.endpoint_config = endpoint_config
|
|
54
53
|
|
|
55
|
-
self.
|
|
56
|
-
self._credentials: str | None = None
|
|
57
|
-
self._headers: Dict[str, Any] | None = None
|
|
54
|
+
self.endpoint_cm = EndpointConfigManager()
|
|
58
55
|
|
|
59
56
|
self.test_batch: ScriptsBatch | None = None
|
|
60
57
|
self.evaluation_verdicts: Dict[str, List[str]] = defaultdict(list)
|
|
@@ -62,36 +59,34 @@ class ConversationSimulator(BaseProcess):
|
|
|
62
59
|
|
|
63
60
|
def setup(
|
|
64
61
|
self,
|
|
65
|
-
|
|
62
|
+
endpoint_config: EndpointConfig,
|
|
66
63
|
evaluators: Dict[EvaluatorType, BaseEvaluator],
|
|
67
64
|
providers: List[str],
|
|
68
|
-
endpoint_config: EndpointConfig,
|
|
69
65
|
) -> None:
|
|
70
66
|
"""
|
|
71
67
|
Initialize the ConversationSimulator.
|
|
72
68
|
|
|
73
69
|
Args:
|
|
74
|
-
|
|
70
|
+
endpoint_config (EndpointConfig): Configuration object for user endpoint API.
|
|
75
71
|
evaluators (Dict[str, BaseEvaluator]): List of evaluator objects for evaluating interactions.
|
|
76
72
|
providers (List[str]): List of LLM provider names.
|
|
77
|
-
|
|
73
|
+
|
|
78
74
|
"""
|
|
79
75
|
_LOG: str = f"[{self._CLASS_NAME}][{self.setup.__name__}]"
|
|
80
76
|
logger.info(f"{_LOG} Setting up the Conversation Simulator..")
|
|
81
77
|
|
|
82
|
-
self.
|
|
78
|
+
if not self.endpoint_cm:
|
|
79
|
+
self.endpoint_cm = EndpointConfigManager()
|
|
80
|
+
|
|
81
|
+
self.endpoint_config = endpoint_config
|
|
82
|
+
self.endpoint_cm.set_endpoints(endpoints_config=[endpoint_config])
|
|
83
|
+
|
|
83
84
|
self.evaluators = evaluators
|
|
84
85
|
self.providers = providers
|
|
85
86
|
|
|
86
87
|
if not self.providers:
|
|
87
88
|
logger.warning(f"{_LOG} No LLM providers were provided. The Judge Evaluation process will not be executed.")
|
|
88
89
|
|
|
89
|
-
self.endpoint_config = endpoint_config
|
|
90
|
-
|
|
91
|
-
self._url = endpoint_config.full_url
|
|
92
|
-
self._credentials = endpoint_config.api_key.get_secret_value()
|
|
93
|
-
self._headers = endpoint_config.headers
|
|
94
|
-
|
|
95
90
|
def get_evaluator(self, name: EvaluatorType) -> BaseEvaluator:
|
|
96
91
|
"""
|
|
97
92
|
Retrieve an evaluator by name.
|
|
@@ -278,22 +273,37 @@ class ConversationSimulator(BaseProcess):
|
|
|
278
273
|
start_time = time.time()
|
|
279
274
|
|
|
280
275
|
results = []
|
|
276
|
+
contextual_mode: bool = script.variable_request_schema
|
|
277
|
+
logger.info(f"{_LOG} Contextual Mode ON: {contextual_mode}")
|
|
281
278
|
interactions = script.interactions
|
|
282
279
|
|
|
283
280
|
for interaction in interactions:
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
281
|
+
if contextual_mode:
|
|
282
|
+
from levelapp.simulator.utils import set_by_path
|
|
283
|
+
request_payload = interaction.request_payload
|
|
284
|
+
user_message = interaction.user_message
|
|
285
|
+
set_by_path(
|
|
286
|
+
obj=request_payload,
|
|
287
|
+
path=interaction.user_message_path,
|
|
288
|
+
value=user_message,
|
|
289
|
+
)
|
|
290
|
+
logger.info(f"{_LOG} Request payload (Variable Request Schema):\n{request_payload}\n---")
|
|
291
|
+
else:
|
|
292
|
+
user_message = interaction.user_message
|
|
293
|
+
request_payload = interaction.request_payload
|
|
294
|
+
request_payload.update({"user_message": user_message})
|
|
295
|
+
logger.info(f"{_LOG} Request payload (Configured Request Schema):\n{request_payload}\n---")
|
|
296
|
+
|
|
297
|
+
mappings = self.endpoint_config.response_mapping
|
|
298
|
+
|
|
299
|
+
response = await self.endpoint_cm.send_request(
|
|
300
|
+
endpoint_config=self.endpoint_config,
|
|
301
|
+
context=request_payload,
|
|
302
|
+
contextual_mode=contextual_mode
|
|
295
303
|
)
|
|
296
304
|
|
|
305
|
+
logger.info(f"{_LOG} Response:\n{response}\n---")
|
|
306
|
+
|
|
297
307
|
reference_reply = interaction.reference_reply
|
|
298
308
|
reference_metadata = interaction.reference_metadata
|
|
299
309
|
reference_guardrail_flag: bool = interaction.guardrail_flag
|
|
@@ -312,14 +322,18 @@ class ConversationSimulator(BaseProcess):
|
|
|
312
322
|
results.append(result)
|
|
313
323
|
continue
|
|
314
324
|
|
|
315
|
-
interaction_details =
|
|
316
|
-
response=response
|
|
317
|
-
|
|
325
|
+
interaction_details = self.endpoint_cm.extract_response_data(
|
|
326
|
+
response=response,
|
|
327
|
+
mappings=mappings,
|
|
318
328
|
)
|
|
319
329
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
330
|
+
logger.info(f"{_LOG} Interaction details:\n{interaction_details}\n---")
|
|
331
|
+
|
|
332
|
+
generated_reply = interaction_details.get("agent_reply", "")
|
|
333
|
+
generated_metadata = interaction_details.get("metadata", {})
|
|
334
|
+
extracted_guardrail_flag = interaction_details.get("guardrail_flag", False)
|
|
335
|
+
|
|
336
|
+
logger.info(f"{_LOG} Generated reply:\n{generated_reply}\n---")
|
|
323
337
|
|
|
324
338
|
evaluation_results = await self.evaluate_interaction(
|
|
325
339
|
user_input=user_message,
|
|
@@ -346,7 +360,7 @@ class ConversationSimulator(BaseProcess):
|
|
|
346
360
|
"reference_reply": reference_reply,
|
|
347
361
|
"generated_metadata": generated_metadata,
|
|
348
362
|
"reference_metadata": reference_metadata,
|
|
349
|
-
"guardrail_details":
|
|
363
|
+
"guardrail_details": extracted_guardrail_flag,
|
|
350
364
|
"evaluation_results": evaluation_results.model_dump(),
|
|
351
365
|
}
|
|
352
366
|
|
levelapp/simulator/utils.py
CHANGED
|
@@ -1,103 +1,74 @@
|
|
|
1
1
|
"""
|
|
2
2
|
'simulators/aspects.py': Utility functions for handling VLA interactions and requests.
|
|
3
3
|
"""
|
|
4
|
-
import ast
|
|
5
|
-
import json
|
|
6
4
|
import httpx
|
|
7
5
|
|
|
8
|
-
from uuid import UUID
|
|
9
|
-
from string import Template
|
|
10
6
|
from typing import Any, Dict, List, Union
|
|
11
7
|
|
|
12
|
-
from pydantic import ValidationError
|
|
13
8
|
|
|
14
9
|
from levelapp.clients import ClientRegistry
|
|
15
10
|
from levelapp.config.prompts import SUMMARIZATION_PROMPT_TEMPLATE
|
|
16
|
-
from levelapp.simulator.schemas import InteractionResults
|
|
17
11
|
from levelapp.aspects import MonitoringAspect, MetricType, logger
|
|
18
12
|
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
def default(self, obj):
|
|
22
|
-
if isinstance(obj, UUID):
|
|
23
|
-
return str(obj)
|
|
24
|
-
return json.JSONEncoder.default(self, obj)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def extract_interaction_details(
|
|
28
|
-
response: str | Dict[str, Any],
|
|
29
|
-
template: Dict[str, Any],
|
|
30
|
-
) -> InteractionResults:
|
|
14
|
+
def set_by_path(obj: Dict, path: str, value: Any) -> None:
|
|
31
15
|
"""
|
|
32
|
-
|
|
16
|
+
Sets a value in a nested dictionary using JSON path-like notation.
|
|
33
17
|
|
|
34
18
|
Args:
|
|
35
|
-
|
|
36
|
-
|
|
19
|
+
obj (dict): Dictionary to modify.
|
|
20
|
+
path (str): Path (e.g., "a.b[0].c") indicating where to set the value.
|
|
21
|
+
value (Any): Value to assign at the specified path.
|
|
37
22
|
|
|
38
23
|
Returns:
|
|
39
|
-
|
|
24
|
+
None
|
|
40
25
|
"""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
try:
|
|
88
|
-
async with httpx.AsyncClient(timeout=180) as client:
|
|
89
|
-
response = await client.post(url=url, headers=headers, json=payload)
|
|
90
|
-
response.raise_for_status()
|
|
91
|
-
|
|
92
|
-
return response
|
|
93
|
-
|
|
94
|
-
except httpx.HTTPStatusError as http_err:
|
|
95
|
-
logger.error(f"[async_interaction_request] HTTP error: {http_err.response.text}", exc_info=True)
|
|
96
|
-
|
|
97
|
-
except httpx.RequestError as req_err:
|
|
98
|
-
logger.error(f"[async_interaction_request] Request error: {str(req_err)}", exc_info=True)
|
|
99
|
-
|
|
100
|
-
return None
|
|
26
|
+
parts = path.split(".")
|
|
27
|
+
current = obj
|
|
28
|
+
|
|
29
|
+
for i, part in enumerate(parts):
|
|
30
|
+
is_last = i == len(parts) - 1
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
# Handle list index access, e.g., key[0] or [1]
|
|
34
|
+
if '[' in part and ']' in part:
|
|
35
|
+
key, idx = part.split('[')
|
|
36
|
+
idx = int(idx.rstrip(']'))
|
|
37
|
+
|
|
38
|
+
# If we have a key before the list
|
|
39
|
+
if key:
|
|
40
|
+
if key not in current or not isinstance(current[key], list):
|
|
41
|
+
current[key] = []
|
|
42
|
+
while len(current[key]) <= idx:
|
|
43
|
+
current[key].append({})
|
|
44
|
+
target = current[key]
|
|
45
|
+
else:
|
|
46
|
+
if not isinstance(current, list):
|
|
47
|
+
print("[set_by_path][WARNING] Expected a list at this level.")
|
|
48
|
+
return
|
|
49
|
+
while len(current) <= idx:
|
|
50
|
+
current.append({})
|
|
51
|
+
target = current
|
|
52
|
+
|
|
53
|
+
if is_last:
|
|
54
|
+
target[idx] = value
|
|
55
|
+
else:
|
|
56
|
+
if not isinstance(target[idx], dict):
|
|
57
|
+
target[idx] = {}
|
|
58
|
+
current = target[idx]
|
|
59
|
+
|
|
60
|
+
else:
|
|
61
|
+
# Regular dictionary key
|
|
62
|
+
if is_last:
|
|
63
|
+
current[part] = value
|
|
64
|
+
else:
|
|
65
|
+
if part not in current or not isinstance(current[part], dict):
|
|
66
|
+
current[part] = {}
|
|
67
|
+
current = current[part]
|
|
68
|
+
|
|
69
|
+
except (KeyError, IndexError, TypeError, AttributeError) as e:
|
|
70
|
+
print(f"[set_by_path][ERROR] Error type <{e.__class__.__name__}> : {e.args[0]}")
|
|
71
|
+
return
|
|
101
72
|
|
|
102
73
|
|
|
103
74
|
@MonitoringAspect.monitor(
|
levelapp/workflow/base.py
CHANGED
|
@@ -7,6 +7,8 @@ from pathlib import Path
|
|
|
7
7
|
from typing import Any, Dict
|
|
8
8
|
|
|
9
9
|
from levelapp.core.base import BaseProcess
|
|
10
|
+
from levelapp.endpoint.client import EndpointConfig
|
|
11
|
+
from levelapp.endpoint.manager import EndpointConfigManager
|
|
10
12
|
from levelapp.simulator.schemas import ScriptsBatch
|
|
11
13
|
from levelapp.simulator.simulator import ConversationSimulator
|
|
12
14
|
from levelapp.workflow.runtime import WorkflowContext
|
|
@@ -68,6 +70,18 @@ class BaseWorkflow(ABC):
|
|
|
68
70
|
"""
|
|
69
71
|
return self._results
|
|
70
72
|
|
|
73
|
+
@abstractmethod
|
|
74
|
+
async def test_connection(self, context: Dict[str, Any]) -> Dict[str, Any]:
|
|
75
|
+
"""
|
|
76
|
+
Abstract method for testing endpoint connection.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
context (Dict[str, Any]): The context (request payload) to test connectivity with.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
The test connectivity result.
|
|
83
|
+
"""
|
|
84
|
+
|
|
71
85
|
@abstractmethod
|
|
72
86
|
def _setup_process(self, context: WorkflowContext) -> BaseProcess:
|
|
73
87
|
"""
|
|
@@ -105,13 +119,30 @@ class SimulatorWorkflow(BaseWorkflow):
|
|
|
105
119
|
"""
|
|
106
120
|
simulator = ConversationSimulator()
|
|
107
121
|
simulator.setup(
|
|
108
|
-
|
|
122
|
+
endpoint_config=context.endpoint,
|
|
109
123
|
evaluators=context.evaluators,
|
|
110
124
|
providers=context.providers,
|
|
111
|
-
endpoint_config=context.endpoint_config,
|
|
112
125
|
)
|
|
126
|
+
|
|
113
127
|
return simulator
|
|
114
128
|
|
|
129
|
+
async def test_connection(self, context: Dict[str, Any]) -> Dict[str, Any]:
|
|
130
|
+
"""
|
|
131
|
+
Runs a connectivity test of the configured endpoint.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
context (Dict[str, Any]): The request payload to send for testing.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
The test connectivity result.
|
|
138
|
+
"""
|
|
139
|
+
endpoint_cm = EndpointConfigManager()
|
|
140
|
+
endpoint_cm.set_endpoints(endpoints_config=[self.context.endpoint])
|
|
141
|
+
tester = endpoint_cm.get_tester(endpoint_name=self.context.endpoint.name)
|
|
142
|
+
results = await tester.test(context=context)
|
|
143
|
+
|
|
144
|
+
return results
|
|
145
|
+
|
|
115
146
|
def _load_input_data(self, context: WorkflowContext) -> Dict[str, Any]:
|
|
116
147
|
"""
|
|
117
148
|
Concrete implementation for loading the reference data.
|
levelapp/workflow/config.py
CHANGED
|
@@ -3,7 +3,7 @@ from typing import List, Dict, Any, Optional
|
|
|
3
3
|
from pydantic import BaseModel, Field
|
|
4
4
|
|
|
5
5
|
from levelapp.aspects import logger
|
|
6
|
-
from levelapp.
|
|
6
|
+
from levelapp.endpoint.client import EndpointConfig
|
|
7
7
|
from levelapp.core.schemas import WorkflowType, RepositoryType, EvaluatorType
|
|
8
8
|
|
|
9
9
|
|
|
@@ -39,9 +39,9 @@ class WorkflowConfig(BaseModel):
|
|
|
39
39
|
Supports both file-based loading and in-memory dictionary creation.
|
|
40
40
|
"""
|
|
41
41
|
process: ProcessConfig
|
|
42
|
+
endpoint: EndpointConfig
|
|
42
43
|
evaluation: EvaluationConfig
|
|
43
44
|
reference_data: ReferenceDataConfig
|
|
44
|
-
endpoint: EndpointConfig
|
|
45
45
|
repository: RepositoryConfig
|
|
46
46
|
|
|
47
47
|
class Config:
|
|
@@ -90,3 +90,7 @@ class WorkflowConfig(BaseModel):
|
|
|
90
90
|
self.reference_data.data = content
|
|
91
91
|
logger.info(f"[{self.__class__.__name__}] Reference data loaded from provided content")
|
|
92
92
|
|
|
93
|
+
|
|
94
|
+
if __name__ == '__main__':
|
|
95
|
+
workflow_config = WorkflowConfig.load(path="../../src/data/workflow_config.yaml")
|
|
96
|
+
print(f"Workflow Configuration:\n{workflow_config.model_dump_json(indent=2)}")
|
levelapp/workflow/context.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""levelapp/workflow/context.py: Builds runtime WorkflowContext from WorkflowConfig."""
|
|
2
2
|
from typing import Dict, Callable
|
|
3
3
|
|
|
4
|
+
from levelapp.repository.filesystem import FileSystemRepository
|
|
4
5
|
from levelapp.workflow.config import WorkflowConfig
|
|
5
6
|
from levelapp.core.base import BaseRepository, BaseEvaluator
|
|
6
7
|
from levelapp.workflow.runtime import WorkflowContext
|
|
@@ -19,6 +20,7 @@ class WorkflowContextBuilder:
|
|
|
19
20
|
# Map repository type to constructor that accepts the WorkflowConfig
|
|
20
21
|
self.repository_map: Dict[RepositoryType, Callable[[WorkflowConfig], BaseRepository]] = {
|
|
21
22
|
RepositoryType.FIRESTORE: lambda cfg: FirestoreRepository(cfg),
|
|
23
|
+
RepositoryType.FILESYSTEM: lambda cfg: FileSystemRepository(cfg),
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
# Map evaluator type to constructor that accepts the WorkflowConfig
|
|
@@ -57,6 +59,6 @@ class WorkflowContextBuilder:
|
|
|
57
59
|
repository=repository,
|
|
58
60
|
evaluators=evaluators,
|
|
59
61
|
providers=providers,
|
|
60
|
-
|
|
62
|
+
endpoint=endpoint_config,
|
|
61
63
|
inputs=inputs,
|
|
62
64
|
)
|
levelapp/workflow/runtime.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from typing import Dict, List, Any
|
|
4
4
|
|
|
5
|
-
from levelapp.
|
|
5
|
+
from levelapp.endpoint.client import EndpointConfig
|
|
6
6
|
from levelapp.core.base import BaseRepository, BaseEvaluator
|
|
7
7
|
from levelapp.workflow.config import WorkflowConfig
|
|
8
8
|
from levelapp.core.schemas import EvaluatorType
|
|
@@ -12,8 +12,8 @@ from levelapp.core.schemas import EvaluatorType
|
|
|
12
12
|
class WorkflowContext:
|
|
13
13
|
"""Immutable data holder for workflow execution context."""
|
|
14
14
|
config: WorkflowConfig
|
|
15
|
+
endpoint: EndpointConfig
|
|
15
16
|
repository: BaseRepository
|
|
16
17
|
evaluators: Dict[EvaluatorType, BaseEvaluator]
|
|
17
18
|
providers: List[str]
|
|
18
|
-
|
|
19
|
-
inputs: Dict[str, Any]
|
|
19
|
+
inputs: Dict[str, Any]
|