model-compose 0.1.8__tar.gz → 0.1.9__tar.gz
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.
- {model_compose-0.1.8/src/model_compose.egg-info → model_compose-0.1.9}/PKG-INFO +1 -1
- {model_compose-0.1.8 → model_compose-0.1.9}/pyproject.toml +1 -1
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/engine/http_client.py +63 -32
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/engine/http_server.py +3 -2
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/engine/mcp_server.py +1 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/runner/http_client.py +3 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/runner/mcp_client.py +3 -2
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/runner/runner.py +10 -1
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/webui/gradio.py +2 -2
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/webui/webui.py +9 -3
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/listener/engine/http_callback.py +8 -8
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/http_client.py +50 -23
- model_compose-0.1.9/src/mindor/core/utils/http_status.py +20 -0
- model_compose-0.1.9/src/mindor/core/utils/mcp_client.py +122 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/streaming.py +2 -2
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/template.py +1 -1
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/http_client.py +4 -4
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/http_client.py +1 -1
- {model_compose-0.1.8 → model_compose-0.1.9/src/model_compose.egg-info}/PKG-INFO +1 -1
- {model_compose-0.1.8 → model_compose-0.1.9}/src/model_compose.egg-info/SOURCES.txt +1 -0
- model_compose-0.1.8/src/mindor/core/utils/mcp_client.py +0 -4
- {model_compose-0.1.8 → model_compose-0.1.9}/LICENSE +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/README.md +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/setup.cfg +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/cli/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/cli/compose.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/component.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/engine/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/engine/base.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/engine/context.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/engine/http_server.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/engine/mcp_client.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/engine/mcp_server.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/component/engine/shell.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/compose/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/compose/compose.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/compose/manager.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/controller.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/engine/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/engine/base.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/runner/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/runner/client.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/webui/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/gateway/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/gateway/engine/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/gateway/engine/base.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/gateway/engine/http_tunnel.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/gateway/engine/ssh_tunnel.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/gateway/gateway.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/listener/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/listener/engine/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/listener/engine/base.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/listener/listener.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/runtime/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/runtime/env.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/services/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/services/async_service.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/expiring.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/http_request.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/image.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/ssh_client.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/time.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/utils/workqueue.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/workflow/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/workflow/context.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/workflow/job.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/workflow/schema.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/workflow/workflow.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/loader.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/action.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/common.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/http_server.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/mcp_client.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/mcp_server.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/shell.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/component.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/common.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/http_server.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/mcp_client.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/mcp_server.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/shell.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/types.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/compose.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/controller.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/common.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/http_server.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/mcp_server.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/types.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/webui.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/gateway.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/impl/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/impl/common.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/impl/http_tunnel.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/impl/ssh_tunnel.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/impl/types.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/listener/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/listener/impl/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/listener/impl/common.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/listener/impl/http_callback.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/listener/impl/types.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/listener/listener.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/runtime/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/runtime/impl/__init__.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/runtime/impl/common.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/runtime/impl/docker.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/runtime/impl/types.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/runtime/runtime.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/workflow.py +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/model_compose.egg-info/dependency_links.txt +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/model_compose.egg-info/entry_points.txt +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/model_compose.egg-info/requires.txt +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/src/model_compose.egg-info/top_level.txt +0 -0
- {model_compose-0.1.8 → model_compose-0.1.9}/tests/test_cli.py +0 -0
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
from typing import Type, Union, Literal, Optional, Dict, List, Tuple, Set, Annotated, AsyncIterator, Any
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
2
3
|
from mindor.dsl.schema.component import HttpClientComponentConfig
|
|
3
4
|
from mindor.dsl.schema.action import ActionConfig, HttpClientActionConfig, HttpClientCompletionConfig
|
|
4
5
|
from mindor.core.listener import HttpCallbackListener
|
|
5
6
|
from mindor.core.utils.http_client import HttpClient
|
|
7
|
+
from mindor.core.utils.http_status import is_status_code_matched
|
|
6
8
|
from mindor.core.utils.time import parse_duration
|
|
7
9
|
from .base import ComponentEngine, ComponentType, ComponentEngineMap
|
|
8
10
|
from .context import ComponentContext
|
|
9
11
|
from datetime import datetime, timezone
|
|
10
12
|
import asyncio
|
|
11
13
|
|
|
12
|
-
class
|
|
13
|
-
|
|
14
|
+
class HttpClientCompletion(ABC):
|
|
15
|
+
@abstractmethod
|
|
16
|
+
async def run(self, context: ComponentContext) -> Any:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
async def close(self) -> None:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
class HttpClientPollingCompletion(HttpClientCompletion):
|
|
24
|
+
def __init__(self, config: HttpClientCompletionConfig, base_url: Optional[str], headers: Optional[Dict[str, str]]):
|
|
25
|
+
self.config: HttpClientCompletionConfig = config
|
|
14
26
|
self.base_url: Optional[str] = base_url
|
|
15
27
|
self.headers: Optional[Dict[str, str]] = headers
|
|
16
|
-
self.config: HttpClientCompletionConfig = config
|
|
17
28
|
self.client: HttpClient = HttpClient()
|
|
18
29
|
|
|
19
30
|
async def run(self, context: ComponentContext) -> Any:
|
|
@@ -30,33 +41,38 @@ class HttpClientPollingCompletion:
|
|
|
30
41
|
await asyncio.sleep(interval.total_seconds())
|
|
31
42
|
|
|
32
43
|
while datetime.now(timezone.utc) < deadline:
|
|
33
|
-
response = await self.client.request(url, method, params, body, headers)
|
|
44
|
+
response, status_code = await self.client.request(url, method, params, body, headers, raise_on_error=False)
|
|
34
45
|
context.register_source("result", response)
|
|
35
46
|
|
|
36
|
-
status = (await context.render_template(self.config.status)) if self.config.status else
|
|
37
|
-
|
|
38
|
-
if not status:
|
|
47
|
+
status = (await context.render_template(self.config.status)) if self.config.status else None
|
|
48
|
+
if self.config.status and not status:
|
|
39
49
|
raise RuntimeError(f"Polling failed: no status found in response.")
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
if status
|
|
51
|
+
if status:
|
|
52
|
+
if status in self.config.success_when or []:
|
|
43
53
|
return response
|
|
44
|
-
|
|
45
|
-
for fail_when in self.config.fail_when if self.config.fail_when else [ "failed" ]:
|
|
46
|
-
if status == await context.render_template(fail_when):
|
|
54
|
+
if status in self.config.fail_when or []:
|
|
47
55
|
raise RuntimeError(f"Polling failed: status '{status}' matched a failure condition.")
|
|
56
|
+
else: # use status code
|
|
57
|
+
if is_status_code_matched(status_code, self.config.success_when or []):
|
|
58
|
+
return response
|
|
59
|
+
if is_status_code_matched(status_code, self.config.fail_when or []):
|
|
60
|
+
raise RuntimeError(f"Polling failed: status code '{status_code}' matched a failure condition.")
|
|
48
61
|
|
|
49
62
|
await asyncio.sleep(interval.total_seconds())
|
|
50
63
|
|
|
51
64
|
raise TimeoutError(f"Polling timed out after {timeout}.")
|
|
52
65
|
|
|
66
|
+
async def close(self) -> None:
|
|
67
|
+
await self.client.close()
|
|
68
|
+
|
|
53
69
|
async def _resolve_request_url(self, context: ComponentContext) -> str:
|
|
54
70
|
if self.base_url and self.config.path:
|
|
55
71
|
return await context.render_template(self.base_url) + await context.render_template(self.config.path)
|
|
56
72
|
|
|
57
73
|
return await context.render_template(self.config.endpoint)
|
|
58
74
|
|
|
59
|
-
class HttpClientCallbackCompletion:
|
|
75
|
+
class HttpClientCallbackCompletion(HttpClientCompletion):
|
|
60
76
|
def __init__(self, config: HttpClientCompletionConfig):
|
|
61
77
|
self.config: HttpClientCompletionConfig = config
|
|
62
78
|
|
|
@@ -66,56 +82,71 @@ class HttpClientCallbackCompletion:
|
|
|
66
82
|
HttpCallbackListener.register_pending_future(callback_id, future)
|
|
67
83
|
|
|
68
84
|
return await future
|
|
85
|
+
|
|
86
|
+
async def close(self) -> None:
|
|
87
|
+
pass
|
|
69
88
|
|
|
70
89
|
class HttpClientAction:
|
|
71
|
-
def __init__(self, base_url: Optional[str], headers: Optional[Dict[str, str]]
|
|
90
|
+
def __init__(self, config: HttpClientActionConfig, base_url: Optional[str], headers: Optional[Dict[str, str]]):
|
|
91
|
+
self.config: HttpClientActionConfig = config
|
|
72
92
|
self.base_url: Optional[str] = base_url
|
|
73
93
|
self.headers: Optional[Dict[str, str]] = headers
|
|
74
|
-
self.
|
|
75
|
-
self.client: HttpClient = HttpClient()
|
|
94
|
+
self.completion: HttpClientCompletion = None
|
|
76
95
|
|
|
77
|
-
|
|
96
|
+
if self.config.completion:
|
|
97
|
+
self._configure_completion()
|
|
98
|
+
|
|
99
|
+
def _configure_completion(self) -> None:
|
|
100
|
+
if self.config.completion.type == "polling":
|
|
101
|
+
self.completion = HttpClientPollingCompletion(self.config.completion, self.base_url, self.headers)
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
if self.config.completion.type == "callback":
|
|
105
|
+
self.completion = HttpClientCallbackCompletion(self.config.completion)
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
raise ValueError(f"Unsupported http completion type: {self.config.completion.type}")
|
|
109
|
+
|
|
110
|
+
async def run(self, context: ComponentContext, client: HttpClient) -> Any:
|
|
78
111
|
url = await self._resolve_request_url(context)
|
|
79
112
|
method = await context.render_template(self.config.method)
|
|
80
113
|
params = await context.render_template(self.config.params)
|
|
81
114
|
body = await context.render_template(self.config.body)
|
|
82
115
|
headers = await context.render_template({ **self.headers, **self.config.headers })
|
|
83
116
|
|
|
84
|
-
response, result = await
|
|
117
|
+
response, result = await client.request(url, method, params, body, headers), None
|
|
85
118
|
context.register_source("response", response)
|
|
86
119
|
|
|
87
|
-
if self.
|
|
88
|
-
result = await self.
|
|
120
|
+
if self.completion:
|
|
121
|
+
result = await self.completion.run(context)
|
|
89
122
|
context.register_source("result", result)
|
|
90
123
|
|
|
91
124
|
return (await context.render_template(self.config.output, ignore_files=True)) if self.config.output else (result or response)
|
|
92
125
|
|
|
126
|
+
async def close(self) -> None:
|
|
127
|
+
if self.completion:
|
|
128
|
+
await self.completion.close()
|
|
129
|
+
|
|
93
130
|
async def _resolve_request_url(self, context: ComponentContext) -> str:
|
|
94
131
|
if self.base_url and self.config.path:
|
|
95
132
|
return await context.render_template(self.base_url) + await context.render_template(self.config.path)
|
|
96
133
|
|
|
97
134
|
return await context.render_template(self.config.endpoint)
|
|
98
135
|
|
|
99
|
-
async def _handle_completion(self, completion: HttpClientCompletionConfig, context: ComponentContext) -> Any:
|
|
100
|
-
if completion.type == "polling":
|
|
101
|
-
return await HttpClientPollingCompletion(self.base_url, self.headers, completion).run(context)
|
|
102
|
-
|
|
103
|
-
if completion.type == "callback":
|
|
104
|
-
return await HttpClientCallbackCompletion(completion).run(context)
|
|
105
|
-
|
|
106
|
-
return None
|
|
107
|
-
|
|
108
136
|
class HttpClientComponent(ComponentEngine):
|
|
109
137
|
def __init__(self, id: str, config: HttpClientComponentConfig, env: Dict[str, str], daemon: bool):
|
|
110
138
|
super().__init__(id, config, env, daemon)
|
|
111
139
|
|
|
140
|
+
self.client: HttpClient = None
|
|
141
|
+
|
|
112
142
|
async def _serve(self) -> None:
|
|
113
|
-
|
|
143
|
+
self.client = HttpClient()
|
|
114
144
|
|
|
115
145
|
async def _shutdown(self) -> None:
|
|
116
|
-
|
|
146
|
+
await self.client.close()
|
|
147
|
+
self.client = None
|
|
117
148
|
|
|
118
149
|
async def _run(self, action: ActionConfig, context: ComponentContext) -> Any:
|
|
119
|
-
return await HttpClientAction(self.config.base_url, self.config.headers
|
|
150
|
+
return await HttpClientAction(action, self.config.base_url, self.config.headers).run(context, self.client)
|
|
120
151
|
|
|
121
152
|
ComponentEngineMap[ComponentType.HTTP_CLIENT] = HttpClientComponent
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/engine/http_server.py
RENAMED
|
@@ -59,7 +59,7 @@ class HttpServerController(ControllerEngine):
|
|
|
59
59
|
self._configure_routes()
|
|
60
60
|
self.app.include_router(self.router, prefix=self.config.base_path)
|
|
61
61
|
|
|
62
|
-
def _configure_server(self):
|
|
62
|
+
def _configure_server(self) -> None:
|
|
63
63
|
self.app.add_middleware(
|
|
64
64
|
CORSMiddleware,
|
|
65
65
|
allow_origins=[self.config.origins],
|
|
@@ -68,7 +68,7 @@ class HttpServerController(ControllerEngine):
|
|
|
68
68
|
allow_headers=["*"],
|
|
69
69
|
)
|
|
70
70
|
|
|
71
|
-
def _configure_routes(self):
|
|
71
|
+
def _configure_routes(self) -> None:
|
|
72
72
|
@self.router.post("/workflows")
|
|
73
73
|
async def run_workflow(
|
|
74
74
|
request: Request
|
|
@@ -107,6 +107,7 @@ class HttpServerController(ControllerEngine):
|
|
|
107
107
|
log_level="info"
|
|
108
108
|
))
|
|
109
109
|
await self.server.serve()
|
|
110
|
+
self.server = None
|
|
110
111
|
|
|
111
112
|
async def _shutdown(self) -> None:
|
|
112
113
|
if self.server:
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/controller/runner/http_client.py
RENAMED
|
@@ -32,6 +32,9 @@ class HttpControllerClient(ControllerClient):
|
|
|
32
32
|
|
|
33
33
|
return await self.client.request(url, method, None, body, headers)
|
|
34
34
|
|
|
35
|
+
async def close(self) -> None:
|
|
36
|
+
await self.client.close()
|
|
37
|
+
|
|
35
38
|
def _flatten_for_multipart(self, body: Dict[str, Any], key: str = "") -> List[Tuple[str, Any]]:
|
|
36
39
|
flattened = []
|
|
37
40
|
|
|
@@ -7,7 +7,8 @@ class McpControllerClient(ControllerClient):
|
|
|
7
7
|
def __init__(self, config: ControllerConfig):
|
|
8
8
|
super().__init__(config)
|
|
9
9
|
|
|
10
|
-
self.client: McpClient = McpClient()
|
|
11
|
-
|
|
12
10
|
async def run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
13
11
|
pass
|
|
12
|
+
|
|
13
|
+
async def close(self) -> None:
|
|
14
|
+
pass
|
|
@@ -13,6 +13,10 @@ class ControllerClient(ABC):
|
|
|
13
13
|
async def run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
14
14
|
pass
|
|
15
15
|
|
|
16
|
+
@abstractmethod
|
|
17
|
+
async def close(self) -> None:
|
|
18
|
+
pass
|
|
19
|
+
|
|
16
20
|
class ControllerRunner:
|
|
17
21
|
def __init__(self, config: ControllerConfig):
|
|
18
22
|
self.config: ControllerConfig = config
|
|
@@ -24,10 +28,15 @@ class ControllerRunner:
|
|
|
24
28
|
if self.config.type == "http-server":
|
|
25
29
|
self.client = HttpControllerClient(self.config)
|
|
26
30
|
return
|
|
27
|
-
|
|
31
|
+
|
|
28
32
|
if self.config.type == "mcp-server":
|
|
29
33
|
self.client = McpControllerClient(self.config)
|
|
30
34
|
return
|
|
35
|
+
|
|
36
|
+
raise ValueError(f"Unsupported controller type: {self.config.type}")
|
|
31
37
|
|
|
32
38
|
async def run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
33
39
|
return await self.client.run_workflow(workflow_id, input)
|
|
40
|
+
|
|
41
|
+
async def close(self) -> None:
|
|
42
|
+
await self.client.close()
|
|
@@ -184,7 +184,7 @@ class GradioWebUIBuilder:
|
|
|
184
184
|
return await load_image_from_stream(Base64StreamResource(value), subtype)
|
|
185
185
|
|
|
186
186
|
if format == "url" and isinstance(value, str):
|
|
187
|
-
return await load_image_from_stream(await HttpClient
|
|
187
|
+
return await load_image_from_stream(await HttpClient.request_once(value), subtype)
|
|
188
188
|
|
|
189
189
|
if isinstance(value, StreamResource):
|
|
190
190
|
return await load_image_from_stream(value, subtype)
|
|
@@ -196,7 +196,7 @@ class GradioWebUIBuilder:
|
|
|
196
196
|
return await save_stream_to_temporary_file(Base64StreamResource(value), subtype)
|
|
197
197
|
|
|
198
198
|
if format == "url" and isinstance(value, str):
|
|
199
|
-
return await save_stream_to_temporary_file(await HttpClient
|
|
199
|
+
return await save_stream_to_temporary_file(await HttpClient.request_once(value), subtype)
|
|
200
200
|
|
|
201
201
|
if isinstance(value, StreamResource):
|
|
202
202
|
return await save_stream_to_temporary_file(value, subtype)
|
|
@@ -30,7 +30,7 @@ class ControllerWebUI(AsyncService):
|
|
|
30
30
|
self.env: Dict[str, str] = env
|
|
31
31
|
self.server: Optional[uvicorn.Server] = None
|
|
32
32
|
self.app: FastAPI = FastAPI(openapi_url=None, docs_url=None, redoc_url=None)
|
|
33
|
-
self.runner: ControllerRunner =
|
|
33
|
+
self.runner: ControllerRunner = None
|
|
34
34
|
|
|
35
35
|
self._configure_driver()
|
|
36
36
|
|
|
@@ -44,6 +44,7 @@ class ControllerWebUI(AsyncService):
|
|
|
44
44
|
return
|
|
45
45
|
|
|
46
46
|
async def _serve(self) -> None:
|
|
47
|
+
self.runner = ControllerRunner(self.controller)
|
|
47
48
|
self.server = uvicorn.Server(uvicorn.Config(
|
|
48
49
|
self.app,
|
|
49
50
|
host=self.config.host,
|
|
@@ -51,10 +52,15 @@ class ControllerWebUI(AsyncService):
|
|
|
51
52
|
log_level="info"
|
|
52
53
|
))
|
|
53
54
|
await self.server.serve()
|
|
55
|
+
await self.runner.close()
|
|
56
|
+
self.server = None
|
|
57
|
+
self.runner = None
|
|
54
58
|
|
|
55
59
|
async def _shutdown(self) -> None:
|
|
56
60
|
if self.server:
|
|
57
61
|
self.server.should_exit = True
|
|
58
|
-
|
|
62
|
+
|
|
59
63
|
async def _run_workflow(self, workflow_id: Optional[str], input: Any) -> Any:
|
|
60
|
-
|
|
64
|
+
if self.runner:
|
|
65
|
+
return await self.runner.run_workflow(workflow_id, input)
|
|
66
|
+
return None
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/core/listener/engine/http_callback.py
RENAMED
|
@@ -22,7 +22,7 @@ class HttpCallbackContext:
|
|
|
22
22
|
self.renderer: TemplateRenderer = TemplateRenderer(self._resolve_source)
|
|
23
23
|
|
|
24
24
|
async def items(self) -> AsyncIterator["HttpCallbackContext"]:
|
|
25
|
-
|
|
25
|
+
for item in await self._items():
|
|
26
26
|
yield HttpCallbackContext(item, self.query, False, None)
|
|
27
27
|
|
|
28
28
|
async def render_template(self, template: str, ignore_files: bool = True) -> Any:
|
|
@@ -56,7 +56,7 @@ class HttpCallbackListener(ListenerEngine):
|
|
|
56
56
|
self._configure_routes()
|
|
57
57
|
self.app.include_router(self.router, prefix=self.config.base_path)
|
|
58
58
|
|
|
59
|
-
def _configure_routes(self):
|
|
59
|
+
def _configure_routes(self) -> None:
|
|
60
60
|
for callback in self.config.callbacks:
|
|
61
61
|
self.router.add_api_route(
|
|
62
62
|
path=callback.path,
|
|
@@ -69,8 +69,8 @@ class HttpCallbackListener(ListenerEngine):
|
|
|
69
69
|
async def _handler(request: Request) -> Response:
|
|
70
70
|
content_type, _ = parse_options_header(request.headers, "Content-Type")
|
|
71
71
|
body, query = await parse_request_body(request, content_type), request.query_params
|
|
72
|
-
context
|
|
73
|
-
succeeded
|
|
72
|
+
context = HttpCallbackContext(body, query, callback.bulk, callback.item)
|
|
73
|
+
succeeded = await self._is_callback_succeeded(callback, context)
|
|
74
74
|
|
|
75
75
|
async for item in context.items():
|
|
76
76
|
callback_id = await item.render_template(callback.identify_by)
|
|
@@ -91,13 +91,12 @@ class HttpCallbackListener(ListenerEngine):
|
|
|
91
91
|
status = (await context.render_template(callback.status)) if callback.status else None
|
|
92
92
|
|
|
93
93
|
if status:
|
|
94
|
-
if
|
|
94
|
+
if status in callback.success_when or []:
|
|
95
95
|
return True
|
|
96
|
-
|
|
97
|
-
if callback.fail_when and status == await context.render_template(callback.fail_when):
|
|
96
|
+
if status in callback.fail_when or []:
|
|
98
97
|
return False
|
|
99
98
|
|
|
100
|
-
return True
|
|
99
|
+
return True
|
|
101
100
|
|
|
102
101
|
async def _serve(self) -> None:
|
|
103
102
|
self.server = uvicorn.Server(uvicorn.Config(
|
|
@@ -107,6 +106,7 @@ class HttpCallbackListener(ListenerEngine):
|
|
|
107
106
|
log_level="info"
|
|
108
107
|
))
|
|
109
108
|
await self.server.serve()
|
|
109
|
+
self.server = None
|
|
110
110
|
|
|
111
111
|
async def _shutdown(self) -> None:
|
|
112
112
|
if self.server:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Optional, Dict, Tuple, AsyncIterator, Any
|
|
1
|
+
from typing import Union, Optional, Dict, Tuple, AsyncIterator, Any
|
|
2
2
|
from .http_request import build_request_body, parse_options_header
|
|
3
3
|
from .streaming import StreamResource
|
|
4
4
|
from requests.structures import CaseInsensitiveDict
|
|
@@ -7,20 +7,19 @@ import aiohttp
|
|
|
7
7
|
class HttpStreamResource(StreamResource):
|
|
8
8
|
def __init__(
|
|
9
9
|
self,
|
|
10
|
-
|
|
11
|
-
stream: aiohttp.StreamReader,
|
|
10
|
+
response: aiohttp.ClientResponse,
|
|
12
11
|
content_type: Optional[str] = None,
|
|
13
12
|
filename: Optional[str] = None
|
|
14
13
|
):
|
|
15
14
|
super().__init__(content_type, filename)
|
|
16
15
|
|
|
17
|
-
self.
|
|
18
|
-
self.stream: aiohttp.StreamReader =
|
|
16
|
+
self.response: aiohttp.ClientResponse = response
|
|
17
|
+
self.stream: aiohttp.StreamReader = response.content
|
|
19
18
|
|
|
20
|
-
async def close(self):
|
|
21
|
-
|
|
22
|
-
self.
|
|
23
|
-
self.stream
|
|
19
|
+
async def close(self) -> None:
|
|
20
|
+
self.response.close()
|
|
21
|
+
self.response = None
|
|
22
|
+
self.stream = None
|
|
24
23
|
|
|
25
24
|
async def _iterate_stream(self) -> AsyncIterator[bytes]:
|
|
26
25
|
_, buffer_size = self.stream.get_read_buffer_limits()
|
|
@@ -33,34 +32,62 @@ class HttpStreamResource(StreamResource):
|
|
|
33
32
|
yield chunk
|
|
34
33
|
|
|
35
34
|
class HttpClient:
|
|
35
|
+
def __init__(self, base_url: Optional[str] = None, headers: Optional[Dict[str, str]] = None):
|
|
36
|
+
self.base_url: Optional[str] = base_url
|
|
37
|
+
self.headers: Optional[Dict[str, str]] = headers
|
|
38
|
+
self.session = aiohttp.ClientSession(self.base_url, headers=self.headers)
|
|
39
|
+
|
|
40
|
+
async def __aenter__(self):
|
|
41
|
+
if self.session is not None:
|
|
42
|
+
self.session = aiohttp.ClientSession(self.base_url, headers=self.headers)
|
|
43
|
+
return self
|
|
44
|
+
|
|
45
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
46
|
+
await self.close()
|
|
47
|
+
|
|
36
48
|
async def request(
|
|
37
49
|
self,
|
|
38
|
-
|
|
50
|
+
url_or_path: str,
|
|
39
51
|
method: Optional[str] = "GET",
|
|
40
52
|
params: Optional[Dict[str, Any]] = None,
|
|
41
53
|
body: Optional[Any] = None,
|
|
42
|
-
headers: Optional[Dict[str, str]] = None
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
headers: Optional[Dict[str, str]] = None,
|
|
55
|
+
raise_on_error: bool = True
|
|
56
|
+
) -> Union[Any, Tuple[Any, int]]:
|
|
57
|
+
response: aiohttp.ClientResponse = None
|
|
45
58
|
try:
|
|
46
|
-
response = await self._request_with_session(session,
|
|
47
|
-
content, _ = await self._parse_response_content(
|
|
59
|
+
response = await self._request_with_session(self.session, url_or_path, method, params, body, headers)
|
|
60
|
+
content, _ = await self._parse_response_content(response)
|
|
48
61
|
|
|
49
|
-
if response.status >= 400:
|
|
62
|
+
if raise_on_error and response.status >= 400:
|
|
50
63
|
raise ValueError(f"Request failed with status {response.status}: {content}")
|
|
51
64
|
|
|
52
65
|
if not isinstance(content, HttpStreamResource):
|
|
53
|
-
|
|
66
|
+
response.close()
|
|
54
67
|
|
|
55
|
-
return content
|
|
68
|
+
return content if raise_on_error else (content, response.status)
|
|
56
69
|
except:
|
|
57
|
-
|
|
70
|
+
if response:
|
|
71
|
+
response.close()
|
|
58
72
|
raise
|
|
59
73
|
|
|
74
|
+
async def close(self) -> None:
|
|
75
|
+
if self.session:
|
|
76
|
+
await self.session.close()
|
|
77
|
+
self.session = None
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
async def request_once(cls, *args, **kwargs):
|
|
81
|
+
instance = cls()
|
|
82
|
+
try:
|
|
83
|
+
return await instance.request(*args, **kwargs)
|
|
84
|
+
finally:
|
|
85
|
+
await instance.close()
|
|
86
|
+
|
|
60
87
|
async def _request_with_session(
|
|
61
88
|
self,
|
|
62
89
|
session: aiohttp.ClientSession,
|
|
63
|
-
|
|
90
|
+
url_or_path: str,
|
|
64
91
|
method: str,
|
|
65
92
|
params: Optional[Dict[str, Any]],
|
|
66
93
|
body: Optional[Any],
|
|
@@ -72,7 +99,7 @@ class HttpClient:
|
|
|
72
99
|
headers = CaseInsensitiveDict(headers)
|
|
73
100
|
headers.pop("Content-Type", None)
|
|
74
101
|
|
|
75
|
-
return await session.request(method,
|
|
102
|
+
return await session.request(method, url_or_path, params=params, data=data, headers=headers)
|
|
76
103
|
|
|
77
104
|
def _build_request_body(self, body: Optional[Any], headers: Optional[Dict[str, str]]) -> Tuple[Any, str]:
|
|
78
105
|
content_type, _ = parse_options_header(headers, "Content-Type")
|
|
@@ -82,7 +109,7 @@ class HttpClient:
|
|
|
82
109
|
|
|
83
110
|
return (body, content_type)
|
|
84
111
|
|
|
85
|
-
async def _parse_response_content(self,
|
|
112
|
+
async def _parse_response_content(self, response: aiohttp.ClientResponse) -> Tuple[Any, str]:
|
|
86
113
|
content_type, _ = parse_options_header(response.headers, "Content-Type")
|
|
87
114
|
|
|
88
115
|
if content_type == "application/json":
|
|
@@ -94,4 +121,4 @@ class HttpClient:
|
|
|
94
121
|
_, disposition = parse_options_header(response.headers, "Content-Disposition")
|
|
95
122
|
filename = disposition.get("filename")
|
|
96
123
|
|
|
97
|
-
return (HttpStreamResource(
|
|
124
|
+
return (HttpStreamResource(response, content_type, filename), content_type)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import Union, List
|
|
2
|
+
|
|
3
|
+
def is_status_code_matched(status_code: int, conditions: List[Union[int, str]]) -> bool:
|
|
4
|
+
for condition in conditions:
|
|
5
|
+
if isinstance(condition, int) or (isinstance(condition, str) and condition.isdigit()):
|
|
6
|
+
if status_code == int(condition):
|
|
7
|
+
return True
|
|
8
|
+
continue
|
|
9
|
+
|
|
10
|
+
if isinstance(condition, str) and condition.endswith("x"):
|
|
11
|
+
try:
|
|
12
|
+
prefix = int(condition.rstrip("x"))
|
|
13
|
+
factor = 10 ** (len(condition) - len(str(prefix)))
|
|
14
|
+
if prefix * factor <= status_code < (prefix + 1) * factor:
|
|
15
|
+
return True
|
|
16
|
+
except ValueError:
|
|
17
|
+
pass
|
|
18
|
+
continue
|
|
19
|
+
|
|
20
|
+
return False
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
from typing import Optional, Dict, Tuple, AsyncIterator, Any
|
|
2
|
+
from mcp.client.streamable_http import streamablehttp_client
|
|
3
|
+
from mcp import ClientSession
|
|
4
|
+
|
|
5
|
+
class McpClient:
|
|
6
|
+
def __init__(self, url: str, headers: Optional[Dict[str, str]] = None):
|
|
7
|
+
self.url: str = url
|
|
8
|
+
self.headers: Optional[Dict[str, str]] = headers
|
|
9
|
+
self.session: Optional[ClientSession] = ClientSession(streamablehttp_client(self.url, headers=self.headers))
|
|
10
|
+
self._initialized = False
|
|
11
|
+
|
|
12
|
+
async def __aenter__(self):
|
|
13
|
+
if self.session is None:
|
|
14
|
+
self.session = ClientSession(streamablehttp_client(self.url, headers=self.headers))
|
|
15
|
+
await self._ensure_initialized()
|
|
16
|
+
return self
|
|
17
|
+
|
|
18
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
19
|
+
await self.close()
|
|
20
|
+
|
|
21
|
+
async def call_tool(self, name: str, arguments: Optional[Dict[str, Any]] = None, raise_on_error: bool = True) -> Any:
|
|
22
|
+
"""
|
|
23
|
+
Call a specific tool on the MCP server
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
name: The name of the tool to call
|
|
27
|
+
arguments: Arguments to pass to the tool
|
|
28
|
+
raise_on_error: Whether to raise exceptions on error responses
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
The tool execution result
|
|
32
|
+
"""
|
|
33
|
+
await self._ensure_initialized()
|
|
34
|
+
try:
|
|
35
|
+
return await self.session.call_tool(name, arguments)
|
|
36
|
+
except:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
async def list_tools(self) -> Any:
|
|
40
|
+
"""List all available tools from the MCP server"""
|
|
41
|
+
await self._ensure_initialized()
|
|
42
|
+
try:
|
|
43
|
+
return await self.session.list_tools()
|
|
44
|
+
except:
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
async def read_resource(self, uri: str, raise_on_error: bool = True) -> Any:
|
|
48
|
+
"""
|
|
49
|
+
Read a specific resource from the MCP server
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
uri: The URI of the resource to read
|
|
53
|
+
raise_on_error: Whether to raise exceptions on error responses
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The resource content
|
|
57
|
+
"""
|
|
58
|
+
await self._ensure_initialized()
|
|
59
|
+
try:
|
|
60
|
+
return await self.session.read_resource(uri)
|
|
61
|
+
except:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
async def list_resources(self) -> Any:
|
|
65
|
+
"""List all available resources from the MCP server"""
|
|
66
|
+
return await self.session.list_resources()
|
|
67
|
+
|
|
68
|
+
async def get_prompt(self, name: str, arguments: Optional[Dict[str, Any]] = None, raise_on_error: bool = True) -> Any:
|
|
69
|
+
"""
|
|
70
|
+
Get a specific prompt from the MCP server
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
name: The name of the prompt to get
|
|
74
|
+
arguments: Arguments to pass to the prompt
|
|
75
|
+
raise_on_error: Whether to raise exceptions on error responses
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
The prompt content
|
|
79
|
+
"""
|
|
80
|
+
await self._ensure_initialized()
|
|
81
|
+
try:
|
|
82
|
+
return await self.session.get_prompt(name, arguments)
|
|
83
|
+
except:
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
async def list_prompts(self) -> Any:
|
|
87
|
+
"""List all available prompts from the MCP server"""
|
|
88
|
+
await self._ensure_initialized()
|
|
89
|
+
try:
|
|
90
|
+
return await self.session.list_prompts()
|
|
91
|
+
except:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
async def ping(self) -> bool:
|
|
95
|
+
"""
|
|
96
|
+
Ping the MCP server to check connectivity
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
True if the server is reachable, False otherwise
|
|
100
|
+
"""
|
|
101
|
+
await self._ensure_initialized()
|
|
102
|
+
try:
|
|
103
|
+
await self.session.send_ping()
|
|
104
|
+
return True
|
|
105
|
+
except:
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
async def close(self) -> None:
|
|
109
|
+
"""Close the MCP client session"""
|
|
110
|
+
await self._close()
|
|
111
|
+
|
|
112
|
+
async def _ensure_initialized(self):
|
|
113
|
+
if not self._initialized:
|
|
114
|
+
await self.session.__aenter__()
|
|
115
|
+
await self.session.initialize()
|
|
116
|
+
self._initialized = True
|
|
117
|
+
|
|
118
|
+
async def _close(self) -> None:
|
|
119
|
+
if self.session:
|
|
120
|
+
await self.session.__aexit__(None, None, None)
|
|
121
|
+
self.session = None
|
|
122
|
+
self._initialized = False
|
|
@@ -19,7 +19,7 @@ class StreamResource(ABC):
|
|
|
19
19
|
return self._iterate_stream()
|
|
20
20
|
|
|
21
21
|
@abstractmethod
|
|
22
|
-
async def close(self):
|
|
22
|
+
async def close(self) -> None:
|
|
23
23
|
pass
|
|
24
24
|
|
|
25
25
|
@abstractmethod
|
|
@@ -37,7 +37,7 @@ class Base64StreamResource(StreamResource):
|
|
|
37
37
|
self.stream = io.BytesIO(base64.b64decode(self.encoded))
|
|
38
38
|
return self
|
|
39
39
|
|
|
40
|
-
async def close(self):
|
|
40
|
+
async def close(self) -> None:
|
|
41
41
|
self.stream.close()
|
|
42
42
|
self.stream = None
|
|
43
43
|
|
|
@@ -128,7 +128,7 @@ class TemplateRenderer:
|
|
|
128
128
|
return await save_stream_to_temporary_file(Base64StreamResource(value), subtype)
|
|
129
129
|
|
|
130
130
|
if format == "url" and isinstance(value, str):
|
|
131
|
-
return await save_stream_to_temporary_file(await HttpClient
|
|
131
|
+
return await save_stream_to_temporary_file(await HttpClient.request_once(value), subtype)
|
|
132
132
|
|
|
133
133
|
if isinstance(value, StreamResource):
|
|
134
134
|
return await save_stream_to_temporary_file(value, subtype)
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/http_client.py
RENAMED
|
@@ -15,8 +15,8 @@ class PollingCompletionConfig(CommonCompletionConfig):
|
|
|
15
15
|
body: Optional[Dict[str, Any]] = Field(default_factory=dict)
|
|
16
16
|
params: Optional[Dict[str, str]] = Field(default_factory=dict)
|
|
17
17
|
status: Optional[str] = None
|
|
18
|
-
success_when: Optional[List[str]] = None
|
|
19
|
-
fail_when: Optional[List[str]] = None
|
|
18
|
+
success_when: Optional[List[Union[int, str]]] = None
|
|
19
|
+
fail_when: Optional[List[Union[int, str]]] = None
|
|
20
20
|
interval: Optional[str] = None
|
|
21
21
|
timeout: Optional[str] = None
|
|
22
22
|
|
|
@@ -28,8 +28,8 @@ class PollingCompletionConfig(CommonCompletionConfig):
|
|
|
28
28
|
|
|
29
29
|
@model_validator(mode="before")
|
|
30
30
|
def normalize_status_fields(cls, values: Dict[str, Any]):
|
|
31
|
-
for key in
|
|
32
|
-
if isinstance(values.get(key), str):
|
|
31
|
+
for key in [ "success_when", "fail_when" ]:
|
|
32
|
+
if isinstance(values.get(key), (int, str)):
|
|
33
33
|
values[key] = [ values[key] ]
|
|
34
34
|
return values
|
|
35
35
|
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/http_client.py
RENAMED
|
@@ -9,7 +9,7 @@ class HttpClientComponentConfig(CommonComponentConfig):
|
|
|
9
9
|
base_url: Optional[str] = None
|
|
10
10
|
headers: Optional[Dict[str, Any]] = Field(default_factory=dict)
|
|
11
11
|
actions: Optional[Dict[str, HttpClientActionConfig]] = Field(default_factory=dict)
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
@model_validator(mode="before")
|
|
14
14
|
def inflate_single_action(cls, values: Dict[str, Any]):
|
|
15
15
|
if "actions" not in values:
|
|
@@ -51,6 +51,7 @@ src/mindor/core/utils/__init__.py
|
|
|
51
51
|
src/mindor/core/utils/expiring.py
|
|
52
52
|
src/mindor/core/utils/http_client.py
|
|
53
53
|
src/mindor/core/utils/http_request.py
|
|
54
|
+
src/mindor/core/utils/http_status.py
|
|
54
55
|
src/mindor/core/utils/image.py
|
|
55
56
|
src/mindor/core/utils/mcp_client.py
|
|
56
57
|
src/mindor/core/utils/ssh_client.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/action/impl/http_server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/http_server.py
RENAMED
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/mcp_client.py
RENAMED
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/component/impl/mcp_server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/http_server.py
RENAMED
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/controller/impl/mcp_server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/impl/http_tunnel.py
RENAMED
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/gateway/impl/ssh_tunnel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{model_compose-0.1.8 → model_compose-0.1.9}/src/mindor/dsl/schema/listener/impl/http_callback.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|