model-compose 0.0.6__tar.gz → 0.0.7__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.
Files changed (90) hide show
  1. {model_compose-0.0.6/src/model_compose.egg-info → model_compose-0.0.7}/PKG-INFO +1 -1
  2. {model_compose-0.0.6 → model_compose-0.0.7}/pyproject.toml +1 -1
  3. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/component/engine/http_client.py +2 -2
  4. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/controller/engine/http_server.py +42 -36
  5. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/workflow/job.py +2 -2
  6. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/workflow/workflow.py +6 -6
  7. {model_compose-0.0.6 → model_compose-0.0.7/src/model_compose.egg-info}/PKG-INFO +1 -1
  8. {model_compose-0.0.6 → model_compose-0.0.7}/LICENSE +0 -0
  9. {model_compose-0.0.6 → model_compose-0.0.7}/README.md +0 -0
  10. {model_compose-0.0.6 → model_compose-0.0.7}/setup.cfg +0 -0
  11. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/__init__.py +0 -0
  12. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/cli/__init__.py +0 -0
  13. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/cli/compose.py +0 -0
  14. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/__init__.py +0 -0
  15. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/component/__init__.py +0 -0
  16. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/component/component.py +0 -0
  17. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/component/engine/__init__.py +0 -0
  18. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/component/engine/base.py +0 -0
  19. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/component/engine/context.py +0 -0
  20. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/component/engine/http_server.py +0 -0
  21. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/compose/__init__.py +0 -0
  22. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/compose/compose.py +0 -0
  23. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/compose/manager.py +0 -0
  24. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/controller/__init__.py +0 -0
  25. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/controller/controller.py +0 -0
  26. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/controller/engine/__init__.py +0 -0
  27. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/controller/engine/base.py +0 -0
  28. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/controller/engine/mcp_server.py +0 -0
  29. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/listener/__init__.py +0 -0
  30. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/listener/engine/__init__.py +0 -0
  31. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/listener/engine/base.py +0 -0
  32. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/listener/engine/http_callback.py +0 -0
  33. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/listener/listener.py +0 -0
  34. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/runtime/__init__.py +0 -0
  35. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/runtime/env.py +0 -0
  36. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/utils/__init__.py +0 -0
  37. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/utils/expiring.py +0 -0
  38. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/utils/http_headers.py +0 -0
  39. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/utils/resources.py +0 -0
  40. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/utils/template.py +0 -0
  41. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/utils/workqueue.py +0 -0
  42. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/workflow/__init__.py +0 -0
  43. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/core/workflow/context.py +0 -0
  44. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/__init__.py +0 -0
  45. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/loader.py +0 -0
  46. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/__init__.py +0 -0
  47. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/action/__init__.py +0 -0
  48. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/action/action.py +0 -0
  49. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/action/impl/__init__.py +0 -0
  50. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/action/impl/common.py +0 -0
  51. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/action/impl/http_client.py +0 -0
  52. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/action/impl/http_server.py +0 -0
  53. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/action/impl/mcp_client.py +0 -0
  54. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/action/impl/mcp_server.py +0 -0
  55. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/__init__.py +0 -0
  56. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/component.py +0 -0
  57. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/impl/__init__.py +0 -0
  58. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/impl/common.py +0 -0
  59. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/impl/http_client.py +0 -0
  60. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/impl/http_server.py +0 -0
  61. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/impl/mcp_client.py +0 -0
  62. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/impl/mcp_server.py +0 -0
  63. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/component/impl/types.py +0 -0
  64. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/compose.py +0 -0
  65. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/controller/__init__.py +0 -0
  66. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/controller/controller.py +0 -0
  67. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/controller/impl/__init__.py +0 -0
  68. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/controller/impl/common.py +0 -0
  69. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/controller/impl/http_server.py +0 -0
  70. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/controller/impl/mcp_server.py +0 -0
  71. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/controller/impl/types.py +0 -0
  72. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/listener/__init__.py +0 -0
  73. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/listener/impl/__init__.py +0 -0
  74. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/listener/impl/common.py +0 -0
  75. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/listener/impl/http_callback.py +0 -0
  76. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/listener/impl/types.py +0 -0
  77. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/listener/listener.py +0 -0
  78. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/runtime/__init__.py +0 -0
  79. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/runtime/impl/__init__.py +0 -0
  80. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/runtime/impl/common.py +0 -0
  81. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/runtime/impl/docker.py +0 -0
  82. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/runtime/impl/types.py +0 -0
  83. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/runtime/runtime.py +0 -0
  84. {model_compose-0.0.6 → model_compose-0.0.7}/src/mindor/dsl/schema/workflow.py +0 -0
  85. {model_compose-0.0.6 → model_compose-0.0.7}/src/model_compose.egg-info/SOURCES.txt +0 -0
  86. {model_compose-0.0.6 → model_compose-0.0.7}/src/model_compose.egg-info/dependency_links.txt +0 -0
  87. {model_compose-0.0.6 → model_compose-0.0.7}/src/model_compose.egg-info/entry_points.txt +0 -0
  88. {model_compose-0.0.6 → model_compose-0.0.7}/src/model_compose.egg-info/requires.txt +0 -0
  89. {model_compose-0.0.6 → model_compose-0.0.7}/src/model_compose.egg-info/top_level.txt +0 -0
  90. {model_compose-0.0.6 → model_compose-0.0.7}/tests/test_cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: model-compose
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: model-compose: Declarative AI Model and Workflow Orchestrator (from Mindor)
5
5
  Author-email: Hanyeol Cho <hanyeol.cho@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "model-compose"
3
- version = "0.0.6"
3
+ version = "0.0.7"
4
4
  description = "model-compose: Declarative AI Model and Workflow Orchestrator (from Mindor)"
5
5
  authors = [
6
6
  { name = "Hanyeol Cho", email = "hanyeol.cho@gmail.com" }
@@ -9,7 +9,7 @@ from urllib.parse import urlencode
9
9
  import aiohttp, json
10
10
 
11
11
  class HttpStreamResource(StreamResource):
12
- def __init__(self, session: aiohttp.ClientSession, stream: aiohttp.StreamReader, filename: Optional[str], content_type: Optional[str]):
12
+ def __init__(self, session: aiohttp.ClientSession, stream: aiohttp.StreamReader, content_type: Optional[str], filename: Optional[str]):
13
13
  super().__init__(content_type, filename)
14
14
 
15
15
  self.session: aiohttp.ClientSession = session
@@ -105,7 +105,7 @@ class HttpClientAction:
105
105
  _, disposition = parse_options_header(response.headers.get("Content-Disposition", ""))
106
106
  filename = disposition.get("filename")
107
107
 
108
- return HttpStreamResource(session, response.content, filename, content_type)
108
+ return HttpStreamResource(session, response.content, content_type, filename)
109
109
 
110
110
  class HttpClientComponent(BaseComponent):
111
111
  def __init__(self, id: str, config: HttpClientComponentConfig, env: Dict[str, str], daemon: bool):
@@ -9,13 +9,13 @@ from mindor.core.utils.resources import StreamResource
9
9
  from .base import BaseController, ControllerType, ControllerEngineMap, TaskState
10
10
 
11
11
  from fastapi import FastAPI, APIRouter, Body, HTTPException
12
- from fastapi.responses import JSONResponse, StreamingResponse
12
+ from fastapi.responses import Response, JSONResponse, StreamingResponse
13
13
  from starlette.background import BackgroundTask
14
14
  import asyncio, uvicorn
15
15
 
16
16
  class WorkflowTaskRequestBody(BaseModel):
17
17
  workflow_id: Optional[str] = None
18
- input: Optional[Dict[str, Any]] = None
18
+ input: Optional[Any] = None
19
19
  wait_for_completion: bool = True
20
20
  output_only: bool = False
21
21
 
@@ -53,22 +53,9 @@ class HttpServerController(BaseController):
53
53
  state = await self.run_workflow(body.workflow_id, body.input, body.wait_for_completion)
54
54
 
55
55
  if body.output_only and body.wait_for_completion:
56
- if state.status == "failed":
57
- raise HTTPException(status_code=500, detail=str(state.error))
58
-
59
- if isinstance(state.output, StreamResource):
60
- return StreamingResponse(
61
- state.output,
62
- media_type=state.output.content_type,
63
- headers = {
64
- "Content-Disposition": f"attachment; filename={state.output.filename}"
65
- } if state.output.filename else {},
66
- #background=BackgroundTask(lambda: asyncio.create_task(state.output.close()))
67
- )
68
-
69
- return state.output
56
+ return self._render_task_output(state)
70
57
 
71
- return JSONResponse(content=TaskResult.from_instance(state).model_dump(exclude_none=True))
58
+ return self._render_task_state(state)
72
59
 
73
60
  @self.router.get("/tasks/{task_id}")
74
61
  async def get_task_state(
@@ -81,25 +68,9 @@ class HttpServerController(BaseController):
81
68
  raise HTTPException(status_code=404, detail="Task not found.")
82
69
 
83
70
  if output_only:
84
- if state.status in [ "pending", "processing" ]:
85
- raise HTTPException(status_code=202, detail="Task is still in progress.")
86
-
87
- if state.status == "failed":
88
- raise HTTPException(status_code=500, detail=str(state.error))
89
-
90
- if isinstance(state.output, StreamResource):
91
- return StreamingResponse(
92
- state.output,
93
- media_type=state.output.content_type,
94
- headers = {
95
- "Content-Disposition": f"attachment; filename={state.output.filename}"
96
- } if state.output.filename else {},
97
- # background=BackgroundTask(lambda: asyncio.create_task(state.output.close()))
98
- )
99
-
100
- return state.output
101
-
102
- return JSONResponse(content=TaskResult.from_instance(state).model_dump(exclude_none=True))
71
+ return self._render_task_output(state)
72
+
73
+ return self._render_task_state(state)
103
74
 
104
75
  async def _serve(self) -> None:
105
76
  self.server = uvicorn.Server(uvicorn.Config(
@@ -113,4 +84,39 @@ class HttpServerController(BaseController):
113
84
  async def _shutdown(self) -> None:
114
85
  self.server.should_exit = True
115
86
 
87
+ def _render_task_output(self, state: TaskState) -> Response:
88
+ if state.status in [ "pending", "processing" ]:
89
+ raise HTTPException(status_code=202, detail="Task is still in progress.")
90
+
91
+ if state.status == "failed":
92
+ raise HTTPException(status_code=500, detail=str(state.error))
93
+
94
+ if isinstance(state.output, StreamResource):
95
+ return self._render_stream_resource(state.output)
96
+
97
+ return JSONResponse(content=state.output)
98
+
99
+ def _render_task_state(self, state: TaskState) -> Response:
100
+ return JSONResponse(content=TaskResult.from_instance(state).model_dump(exclude_none=True))
101
+
102
+ def _render_stream_resource(self, resource: StreamResource) -> Response:
103
+ def _close_stream():
104
+ asyncio.run(resource.close())
105
+
106
+ return StreamingResponse(
107
+ resource,
108
+ media_type=resource.content_type,
109
+ headers=self._build_stream_resource_headers(resource),
110
+ background=BackgroundTask(_close_stream)
111
+ )
112
+
113
+ def _build_stream_resource_headers(self, resource: StreamResource) -> Dict[str, str]:
114
+ headers: Dict[str, str] = { "Cache-Control": "no-cache" }
115
+
116
+ if resource.filename:
117
+ filename = resource.filename.replace('"', '\\"')
118
+ headers["Content-Disposition"] = f'attachment; filename="{filename}"'
119
+
120
+ return headers
121
+
116
122
  ControllerEngineMap[ControllerType.HTTP_SERVER] = HttpServerController
@@ -12,13 +12,13 @@ class Job:
12
12
  self.component_provider: Callable[[Union[ComponentConfig, str]], BaseComponent] = component_provider
13
13
 
14
14
  async def run(self, context: WorkflowContext) -> Any:
15
- component = self.component_provider(self.config.component)
15
+ component = self.component_provider(self.id, self.config.component)
16
16
 
17
17
  if not component.started:
18
18
  await component.start()
19
19
 
20
20
  call_id = ulid.ulid()
21
- input = context.render_template(self.config.input) if self.config.output else context.input
21
+ input = context.render_template(self.config.input) if self.config.input else context.input
22
22
  output = await component.run(self.config.action, call_id, input)
23
23
 
24
24
  if output:
@@ -76,9 +76,9 @@ class WorkflowResolver:
76
76
  return default_ids[0] if default_ids else "__default__"
77
77
 
78
78
  class WorkflowRunner:
79
- def __init__(self, jobs: Dict[str, JobConfig], component_provider: Callable[[Union[ComponentConfig, str]], BaseComponent]):
79
+ def __init__(self, jobs: Dict[str, JobConfig], component_provider: Callable[[Union[str, ComponentConfig, str]], BaseComponent]):
80
80
  self.jobs: Dict[str, JobConfig] = jobs
81
- self.component_provider: Callable[[Union[ComponentConfig, str]], BaseComponent] = component_provider
81
+ self.component_provider: Callable[[Union[str, ComponentConfig, str]], BaseComponent] = component_provider
82
82
 
83
83
  async def run(self, context: WorkflowContext) -> Any:
84
84
  pending_jobs: Dict[str, Job] = { job_id: Job(job_id, job, self.component_provider) for job_id, job in self.jobs.items() }
@@ -144,14 +144,14 @@ class Workflow:
144
144
  def validate(self) -> None:
145
145
  JobGraphValidator(self.config.jobs).validate()
146
146
 
147
- def _create_component(self, component: Union[ComponentConfig, str]) -> BaseComponent:
148
- return create_component(*self._resolve_component(component), env=self.env, daemon=False)
147
+ def _create_component(self, id: str, component: Union[ComponentConfig, str]) -> BaseComponent:
148
+ return create_component(*self._resolve_component(id, component), env=self.env, daemon=False)
149
149
 
150
- def _resolve_component(self, component: Union[ComponentConfig, str]) -> Tuple[str, ComponentConfig]:
150
+ def _resolve_component(self, id: str, component: Union[ComponentConfig, str]) -> Tuple[str, ComponentConfig]:
151
151
  if isinstance(component, str):
152
152
  return ComponentResolver(self.components).resolve(component)
153
153
 
154
- return self.id, component
154
+ return id, component
155
155
 
156
156
  def create_workflow(id: str, config: WorkflowConfig, components: Dict[str, ComponentConfig], env: Dict[str, str]) -> Workflow:
157
157
  return Workflow(id, config, components, env)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: model-compose
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: model-compose: Declarative AI Model and Workflow Orchestrator (from Mindor)
5
5
  Author-email: Hanyeol Cho <hanyeol.cho@gmail.com>
6
6
  License-Expression: MIT
File without changes
File without changes
File without changes