service-forge 0.1.18__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 service-forge might be problematic. Click here for more details.

Files changed (83) hide show
  1. service_forge/api/deprecated_websocket_api.py +86 -0
  2. service_forge/api/deprecated_websocket_manager.py +425 -0
  3. service_forge/api/http_api.py +152 -0
  4. service_forge/api/http_api_doc.py +455 -0
  5. service_forge/api/kafka_api.py +126 -0
  6. service_forge/api/routers/feedback/feedback_router.py +148 -0
  7. service_forge/api/routers/service/service_router.py +127 -0
  8. service_forge/api/routers/websocket/websocket_manager.py +83 -0
  9. service_forge/api/routers/websocket/websocket_router.py +78 -0
  10. service_forge/api/task_manager.py +141 -0
  11. service_forge/current_service.py +14 -0
  12. service_forge/db/__init__.py +1 -0
  13. service_forge/db/database.py +237 -0
  14. service_forge/db/migrations/feedback_migration.py +154 -0
  15. service_forge/db/models/__init__.py +0 -0
  16. service_forge/db/models/feedback.py +33 -0
  17. service_forge/llm/__init__.py +67 -0
  18. service_forge/llm/llm.py +56 -0
  19. service_forge/model/__init__.py +0 -0
  20. service_forge/model/feedback.py +30 -0
  21. service_forge/model/websocket.py +13 -0
  22. service_forge/proto/foo_input.py +5 -0
  23. service_forge/service.py +280 -0
  24. service_forge/service_config.py +44 -0
  25. service_forge/sft/cli.py +91 -0
  26. service_forge/sft/cmd/config_command.py +67 -0
  27. service_forge/sft/cmd/deploy_service.py +123 -0
  28. service_forge/sft/cmd/list_tars.py +41 -0
  29. service_forge/sft/cmd/service_command.py +149 -0
  30. service_forge/sft/cmd/upload_service.py +36 -0
  31. service_forge/sft/config/injector.py +129 -0
  32. service_forge/sft/config/injector_default_files.py +131 -0
  33. service_forge/sft/config/sf_metadata.py +30 -0
  34. service_forge/sft/config/sft_config.py +200 -0
  35. service_forge/sft/file/__init__.py +0 -0
  36. service_forge/sft/file/ignore_pattern.py +80 -0
  37. service_forge/sft/file/sft_file_manager.py +107 -0
  38. service_forge/sft/kubernetes/kubernetes_manager.py +257 -0
  39. service_forge/sft/util/assert_util.py +25 -0
  40. service_forge/sft/util/logger.py +16 -0
  41. service_forge/sft/util/name_util.py +8 -0
  42. service_forge/sft/util/yaml_utils.py +57 -0
  43. service_forge/storage/__init__.py +5 -0
  44. service_forge/storage/feedback_storage.py +245 -0
  45. service_forge/utils/__init__.py +0 -0
  46. service_forge/utils/default_type_converter.py +12 -0
  47. service_forge/utils/register.py +39 -0
  48. service_forge/utils/type_converter.py +99 -0
  49. service_forge/utils/workflow_clone.py +124 -0
  50. service_forge/workflow/__init__.py +1 -0
  51. service_forge/workflow/context.py +14 -0
  52. service_forge/workflow/edge.py +24 -0
  53. service_forge/workflow/node.py +184 -0
  54. service_forge/workflow/nodes/__init__.py +8 -0
  55. service_forge/workflow/nodes/control/if_node.py +29 -0
  56. service_forge/workflow/nodes/control/switch_node.py +28 -0
  57. service_forge/workflow/nodes/input/console_input_node.py +26 -0
  58. service_forge/workflow/nodes/llm/query_llm_node.py +41 -0
  59. service_forge/workflow/nodes/nested/workflow_node.py +28 -0
  60. service_forge/workflow/nodes/output/kafka_output_node.py +27 -0
  61. service_forge/workflow/nodes/output/print_node.py +29 -0
  62. service_forge/workflow/nodes/test/if_console_input_node.py +33 -0
  63. service_forge/workflow/nodes/test/time_consuming_node.py +62 -0
  64. service_forge/workflow/port.py +89 -0
  65. service_forge/workflow/trigger.py +28 -0
  66. service_forge/workflow/triggers/__init__.py +6 -0
  67. service_forge/workflow/triggers/a2a_api_trigger.py +257 -0
  68. service_forge/workflow/triggers/fast_api_trigger.py +201 -0
  69. service_forge/workflow/triggers/kafka_api_trigger.py +47 -0
  70. service_forge/workflow/triggers/once_trigger.py +23 -0
  71. service_forge/workflow/triggers/period_trigger.py +29 -0
  72. service_forge/workflow/triggers/websocket_api_trigger.py +189 -0
  73. service_forge/workflow/workflow.py +227 -0
  74. service_forge/workflow/workflow_callback.py +141 -0
  75. service_forge/workflow/workflow_config.py +66 -0
  76. service_forge/workflow/workflow_event.py +15 -0
  77. service_forge/workflow/workflow_factory.py +246 -0
  78. service_forge/workflow/workflow_group.py +51 -0
  79. service_forge/workflow/workflow_type.py +52 -0
  80. service_forge-0.1.18.dist-info/METADATA +98 -0
  81. service_forge-0.1.18.dist-info/RECORD +83 -0
  82. service_forge-0.1.18.dist-info/WHEEL +4 -0
  83. service_forge-0.1.18.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,246 @@
1
+ import uuid
2
+ from omegaconf import OmegaConf
3
+ from typing import Callable, Awaitable, AsyncIterator, Any
4
+ from copy import deepcopy
5
+
6
+ from service_forge.workflow.workflow_callback import BuiltinWorkflowCallback
7
+ from .workflow import Workflow
8
+ from .workflow_group import WorkflowGroup, WORKFLOW_DEFAULT_VERSION
9
+ from .node import Node
10
+ from .edge import Edge
11
+ from .port import Port, parse_port_name, create_workflow_input_port, create_sub_workflow_input_port
12
+ from .node import node_register
13
+ from .nodes import *
14
+ from .triggers import *
15
+ from .context import Context
16
+ from ..db.database import DatabaseManager
17
+ from .workflow_config import WorkflowConfig, WorkflowGroupConfig
18
+
19
+ # WORKFLOW_KEY_NAME = 'name'
20
+ # WORKFLOW_KEY_DESCRIPTION = 'description'
21
+ # WORKFLOW_KEY_VERSION = 'version'
22
+ # WORKFLOW_KEY_NODES = 'nodes'
23
+ # WORKFLOW_KEY_INPUTS = 'inputs'
24
+ # WORKFLOW_KEY_OUTPUTS = 'outputs'
25
+
26
+ # NODE_KEY_NAME = 'name'
27
+ # NODE_KEY_TYPE = 'type'
28
+ # NODE_KEY_ARGS = 'args'
29
+ # NODE_KEY_OUTPUTS = 'outputs'
30
+ # # NODE_KEY_INPUT_PORTS = 'input_ports'
31
+ # # NODE_KEY_OUTPUT_PORTS = 'output_ports'
32
+ # NODE_KEY_SUB_WORKFLOWS = 'sub_workflows'
33
+ # NODE_KEY_SUB_WORKFLOWS_INPUT_PORTS = 'sub_workflows_input_ports'
34
+
35
+ # PORT_KEY_NAME = 'name'
36
+ # PORT_KEY_PORT = 'port'
37
+ # PORT_KEY_VALUE = 'value'
38
+
39
+ def parse_argument(arg: Any, service_env: dict[str, Any] = None) -> Any:
40
+ # TODO: support import variables
41
+ if type(arg) == str and arg.startswith(f'<{{') and arg.endswith(f'}}>'):
42
+ key = arg[2:-2]
43
+ if key not in service_env:
44
+ raise ValueError(f"Key {key} not found in service env.")
45
+ return service_env[key]
46
+ return arg
47
+
48
+ def create_workflow(
49
+ config_path: str = None,
50
+ config: WorkflowConfig = None,
51
+ service_env: dict[str, Any] = None,
52
+ workflows: WorkflowGroup = None,
53
+ _handle_stream_output: Callable[[str, AsyncIterator[str]], Awaitable[None]] | None = None,
54
+ _handle_query_user: Callable[[str, str], Awaitable[str]] | None = None,
55
+ database_manager: DatabaseManager = None,
56
+ ) -> Workflow:
57
+ if config is None:
58
+ if config_path is not None:
59
+ config = WorkflowConfig.from_yaml_file(config_path)
60
+ else:
61
+ raise ValueError("Either config_path or config must be provided")
62
+
63
+ workflow = Workflow(
64
+ id = uuid.uuid4(),
65
+ config = config,
66
+ nodes = [],
67
+ input_ports = [],
68
+ output_ports = [],
69
+ _handle_stream_output = _handle_stream_output,
70
+ _handle_query_user = _handle_query_user,
71
+ database_manager = database_manager,
72
+ # TODO: max_concurrent_runs
73
+ callbacks = [BuiltinWorkflowCallback()],
74
+ )
75
+
76
+ nodes: dict[str, Node] = {}
77
+
78
+ for node_config in config.nodes:
79
+ params = {
80
+ "name": node_config.name,
81
+ }
82
+
83
+ node: Node = node_register.instance(node_config.type, ignore_keys=['type'], kwargs=params)
84
+
85
+ # Context
86
+ node.context = Context(variables = {})
87
+
88
+ # Input ports
89
+ node.input_ports = deepcopy(node.DEFAULT_INPUT_PORTS)
90
+ for input_port in node.input_ports:
91
+ input_port.node = node
92
+
93
+ # Output ports
94
+ node.output_ports = deepcopy(node.DEFAULT_OUTPUT_PORTS)
95
+ for output_port in node.output_ports:
96
+ output_port.node = node
97
+
98
+ # Sub workflows
99
+ if node_config.sub_workflows is not None:
100
+ sub_workflows: WorkflowGroup = WorkflowGroup(workflows=[])
101
+ for sub_workflow_config in node_config.sub_workflows:
102
+ sub_workflow = workflows.get_workflow_by_name(sub_workflow_config.name, sub_workflow_config.version)
103
+ sub_workflows.add_workflow(deepcopy(sub_workflow))
104
+ node.sub_workflows = sub_workflows
105
+
106
+ # Sub workflows input ports
107
+ if node_config.sub_workflows_input_ports is not None:
108
+ for sub_workflow_input_port_config in node_config.sub_workflows_input_ports:
109
+ name = sub_workflow_input_port_config.name
110
+ sub_workflow_name, sub_workflow_port_name = parse_port_name(sub_workflow_input_port_config.port)
111
+ sub_workflow = node.sub_workflows.get_workflow_by_name(sub_workflow_name, sub_workflow_config.version)
112
+ if sub_workflow is None:
113
+ raise ValueError(f"{sub_workflow_name} is not a valid sub workflow.")
114
+ sub_workflow_port = sub_workflow.get_input_port_by_name(sub_workflow_port_name)
115
+ if sub_workflow_port is None:
116
+ raise ValueError(f"{sub_workflow_port_name} is not a valid input port.")
117
+ value = sub_workflow_input_port_config.value
118
+ node.input_ports.append(create_sub_workflow_input_port(name=name, node=node, port=sub_workflow_port, value=value))
119
+
120
+ # Sub workflows output ports
121
+ ...
122
+
123
+ # Hooks
124
+ if _handle_query_user is None:
125
+ node.query_user = workflow.handle_query_user
126
+ else:
127
+ node.query_user = _handle_query_user
128
+
129
+ nodes[node_config.name] = node
130
+
131
+ # Edges
132
+ for node_config in config.nodes:
133
+ start_node = nodes[node_config.name]
134
+ if node_config.outputs is not None:
135
+ for key, value in node_config.outputs.items():
136
+ if value is None:
137
+ continue
138
+
139
+ if type(value) is str:
140
+ value = [value]
141
+
142
+ for edge_value in value:
143
+ end_node_name, end_port_name = parse_port_name(edge_value)
144
+ end_node = nodes[end_node_name]
145
+
146
+ start_node.try_create_extended_output_port(key)
147
+ end_node.try_create_extended_input_port(end_port_name)
148
+
149
+ start_port = start_node.get_output_port_by_name(key)
150
+ end_port = end_node.get_input_port_by_name(end_port_name)
151
+
152
+ if start_port is None:
153
+ raise ValueError(f"{key} is not a valid output port.")
154
+ if end_port is None:
155
+ raise ValueError(f"{end_port_name} is not a valid input port.")
156
+
157
+ edge = Edge(start_node, end_node, start_port, end_port)
158
+
159
+ start_node.output_edges.append(edge)
160
+ end_node.input_edges.append(edge)
161
+
162
+ workflow.add_nodes(list(nodes.values()))
163
+
164
+ # Inputs
165
+ if config.inputs is not None:
166
+ for port_config in config.inputs:
167
+ name = port_config.name
168
+ node_name, node_port_name = parse_port_name(port_config.port)
169
+ if node_name not in nodes:
170
+ raise ValueError(f"{node_name} is not a valid node.")
171
+ node = nodes[node_name]
172
+ port = node.get_input_port_by_name(node_port_name)
173
+ if port is None:
174
+ raise ValueError(f"{node_port_name} is not a valid input port.")
175
+ value = port_config.value
176
+ workflow.input_ports.append(create_workflow_input_port(name=name, port=port, value=value))
177
+
178
+ # Outputs
179
+ if config.outputs is not None:
180
+ for port_config in config.outputs:
181
+ name = port_config.name
182
+ node_name, node_port_name = parse_port_name(port_config.port)
183
+ if node_name not in nodes:
184
+ raise ValueError(f"{node_name} is not a valid node.")
185
+ node = nodes[node_name]
186
+ port = node.get_output_port_by_name(node_port_name)
187
+ if port is None:
188
+ raise ValueError(f"{node_port_name} is not a valid output port.")
189
+ output_port = Port(name=name, type=Any, port=port)
190
+ workflow.output_ports.append(output_port)
191
+ edge = Edge(node, None, port, output_port)
192
+ node.output_edges.append(edge)
193
+
194
+ for node_config in config.nodes:
195
+ node = nodes[node_config.name]
196
+ # Arguments
197
+ if node_config.args is not None:
198
+ for key, value in node_config.args.items():
199
+ node.fill_input_by_name(key, parse_argument(value, service_env=service_env))
200
+
201
+ return workflow
202
+
203
+ def create_workflow_group(
204
+ config_path: str = None,
205
+ config: WorkflowConfig | WorkflowGroupConfig = None,
206
+ service_env: dict[str, Any] = None,
207
+ _handle_stream_output: Callable[[str, AsyncIterator[str]], Awaitable[None]] = None,
208
+ _handle_query_user: Callable[[str, str], Awaitable[str]] = None,
209
+ database_manager: DatabaseManager = None,
210
+ ) -> WorkflowGroup:
211
+
212
+ if config is None:
213
+ if config_path is not None:
214
+ try:
215
+ config = WorkflowGroupConfig.from_yaml_file(config_path)
216
+ except:
217
+ config = WorkflowConfig.from_yaml_file(config_path)
218
+ else:
219
+ raise ValueError("Either config_path or config must be provided")
220
+
221
+ if type(config) == WorkflowConfig:
222
+ workflow = create_workflow(
223
+ config_path=config_path if config_path else None,
224
+ config=config,
225
+ service_env=service_env,
226
+ _handle_stream_output=_handle_stream_output,
227
+ _handle_query_user=_handle_query_user,
228
+ database_manager=database_manager,
229
+ )
230
+ return WorkflowGroup(workflows=[workflow], main_workflow_name=workflow.name, main_workflow_version=workflow.version)
231
+ elif type(config) == WorkflowGroupConfig:
232
+ workflows = WorkflowGroup(
233
+ workflows=[],
234
+ main_workflow_name=config.main_workflow_name,
235
+ main_workflow_version=config.main_workflow_version,
236
+ )
237
+ for workflow_config in config.workflows:
238
+ workflows.add_workflow(create_workflow(
239
+ config=workflow_config,
240
+ workflows=workflows,
241
+ service_env=service_env,
242
+ _handle_stream_output=_handle_stream_output,
243
+ _handle_query_user=_handle_query_user,
244
+ database_manager=database_manager,
245
+ ))
246
+ return workflows
@@ -0,0 +1,51 @@
1
+ import uuid
2
+ from service_forge.workflow.workflow import Workflow
3
+
4
+ WORKFLOW_DEFAULT_VERSION = "0"
5
+ WORKFLOW_MAIN_WORKFLOW_NAME = "main"
6
+
7
+ class WorkflowGroup:
8
+ def __init__(
9
+ self,
10
+ workflows: list[Workflow],
11
+ main_workflow_name: str = WORKFLOW_MAIN_WORKFLOW_NAME,
12
+ main_workflow_version: str = WORKFLOW_DEFAULT_VERSION,
13
+ ) -> None:
14
+ self.workflows = workflows
15
+ self.main_workflow_name = main_workflow_name
16
+ self.main_workflow_version = main_workflow_version
17
+
18
+ def add_workflow(self, workflow: Workflow) -> None:
19
+ self.workflows.append(workflow)
20
+
21
+ def get_workflow_by_name(self, name: str, version: str) -> Workflow | None:
22
+ for workflow in self.workflows:
23
+ if workflow.name == name and workflow.version == version:
24
+ return workflow
25
+ return None
26
+
27
+ def get_workflow_by_id(self, id: uuid.UUID) -> Workflow | None:
28
+ for workflow in self.workflows:
29
+ print(workflow.name, workflow.id, id)
30
+ if workflow.id == id:
31
+ return workflow
32
+ return None
33
+
34
+ def get_main_workflow(self, allow_none: bool = True) -> Workflow | None:
35
+ workflow = self.get_workflow_by_name(self.main_workflow_name, self.main_workflow_version)
36
+ if not allow_none and workflow is None:
37
+ raise ValueError(f"Main workflow with name {self.main_workflow_name} and version {self.main_workflow_version} not found in workflow group.")
38
+ return workflow
39
+
40
+ async def run(self, name: str = None, version: str = None, id: uuid.UUID = None) -> None:
41
+ if name is None and id is None:
42
+ workflow = self.get_main_workflow()
43
+ elif name is not None:
44
+ workflow = self.get_workflow_by_name(name, version)
45
+ elif id is not None:
46
+ workflow = self.get_workflow_by_id(id)
47
+ else:
48
+ workflow = None
49
+ if workflow is None:
50
+ raise ValueError(f"Workflow with name {name} and version {version} and id {id} not found in workflow group.")
51
+ await workflow.run()
@@ -0,0 +1,52 @@
1
+ from __future__ import annotations
2
+ import os
3
+ import importlib
4
+ import inspect
5
+ from pathlib import Path
6
+ from typing import Type, Any
7
+
8
+ from service_forge.utils.register import Register
9
+
10
+ class WorkflowType:
11
+ CLASS_NOT_REQUIRED_TO_REGISTER = ['WorkflowType']
12
+
13
+ def __init__(self, name: str, type: type) -> None:
14
+ self.name = name
15
+ self.type = type
16
+
17
+ def __init_subclass__(cls) -> None:
18
+ if cls.__name__ not in WorkflowType.CLASS_NOT_REQUIRED_TO_REGISTER:
19
+ workflow_type_register.register(cls.__name__, cls)
20
+ return super().__init_subclass__()
21
+
22
+ workflow_type_register = Register[WorkflowType]()
23
+
24
+ def _load_proto_classes():
25
+ # TODO: load from config
26
+ proto_dir = Path(__file__).parent.parent / "proto"
27
+
28
+ if not proto_dir.exists():
29
+ return
30
+
31
+ for py_file in proto_dir.glob("*.py"):
32
+ if py_file.name == "__init__.py":
33
+ continue
34
+
35
+ module_name = py_file.stem
36
+ module_path = f"service_forge.proto.{module_name}"
37
+
38
+ try:
39
+ module = importlib.import_module(module_path)
40
+
41
+ for name, obj in inspect.getmembers(module, inspect.isclass):
42
+ if (not name.startswith('_') and
43
+ obj.__module__ == module_path and
44
+ hasattr(obj, '__bases__')):
45
+
46
+ workflow_type = WorkflowType(name, obj)
47
+ workflow_type_register.register(name, workflow_type)
48
+
49
+ except Exception as e:
50
+ print(f"Failed to load module {module_path}: {e}")
51
+
52
+ _load_proto_classes()
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: service-forge
3
+ Version: 0.1.18
4
+ Summary: Add your description here
5
+ Author-email: euxcet <zcc.qwer@gmail.com>
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: a2a-sdk>=0.3.22
8
+ Requires-Dist: aiokafka>=0.12.0
9
+ Requires-Dist: alembic>=1.17.0
10
+ Requires-Dist: asyncpg>=0.30.0
11
+ Requires-Dist: dotenv>=0.9.9
12
+ Requires-Dist: fastapi>=0.119.1
13
+ Requires-Dist: greenlet>=3.2.4
14
+ Requires-Dist: jinja2>=3.1.6
15
+ Requires-Dist: kubernetes>=28.0.0
16
+ Requires-Dist: loguru>=0.7.3
17
+ Requires-Dist: omegaconf>=2.3.0
18
+ Requires-Dist: openai>=2.3.0
19
+ Requires-Dist: protobuf>=6.33.1
20
+ Requires-Dist: psycopg2-binary>=2.9.11
21
+ Requires-Dist: pydantic>=2.12.0
22
+ Requires-Dist: pymongo>=4.15.5
23
+ Requires-Dist: pytest-asyncio>=1.2.0
24
+ Requires-Dist: pytest>=8.4.2
25
+ Requires-Dist: python-dotenv>=1.1.1
26
+ Requires-Dist: python-jose>=3.5.0
27
+ Requires-Dist: python-multipart>=0.0.20
28
+ Requires-Dist: redis>=7.1.0
29
+ Requires-Dist: requests>=2.32.5
30
+ Requires-Dist: restrictedpython>=8.0
31
+ Requires-Dist: rich>=13.0.0
32
+ Requires-Dist: sqlalchemy>=2.0.44
33
+ Requires-Dist: typer>=0.12.0
34
+ Requires-Dist: uvicorn>=0.38.0
35
+ Requires-Dist: websockets>=15.0.1
36
+ Description-Content-Type: text/markdown
37
+
38
+ # Service Forge
39
+
40
+ Automated service creation and maintenance tool.
41
+
42
+ ## Install
43
+
44
+ ```bash
45
+ pip install -e .
46
+ ```
47
+
48
+ ## CLI Usage (sft)
49
+
50
+ Service Forge 提供了命令行工具 `sft` 用于服务管理。
51
+
52
+ ### 服务上传和部署
53
+
54
+ ```bash
55
+ # 上传服务(打包并上传到服务器)
56
+ sft upload [project_path]
57
+
58
+ # 列出本地已打包的服务包
59
+ sft list
60
+
61
+ # 部署服务(只在服务器上使用)
62
+ sft deploy <name> <version>
63
+ ```
64
+
65
+ ### 配置管理
66
+
67
+ ```bash
68
+ # 列出所有配置项
69
+ sft config list
70
+
71
+ # 获取指定配置项的值
72
+ sft config get <key>
73
+
74
+ # 设置配置项的值
75
+ sft config set <key> <value>
76
+ ```
77
+
78
+ ### 服务管理
79
+
80
+ ```bash
81
+ # 列出所有服务
82
+ sft service list
83
+
84
+ # 删除服务(只在服务器上使用)
85
+ sft service delete <service_name> [--force, -f]
86
+
87
+ # 查看服务日志(只在服务器上使用)
88
+ sft service logs <service_name> [--container, -c] [--tail, -n] [--follow, -f] [--previous, -p]
89
+ ```
90
+
91
+ ## TODO
92
+
93
+ - [x] 多次 trigger 并行执行
94
+ - [x] 支持 websocket 来做 trigger、输入和输出
95
+ - [x] 优化 websocket 客户端映射和重连支持
96
+ - [x] 节点和 workflow 运行情况的回调函数
97
+ - [ ] 支持 a2a
98
+ - [ ] workflow 执行异常处理
@@ -0,0 +1,83 @@
1
+ service_forge/current_service.py,sha256=0YKm7nQiXzUUAc1ToCcbG1QPJfOSNKcOHUpyJ4E3xrY,342
2
+ service_forge/service.py,sha256=rZZ7-BXTTCrc6KqnONnKpg-bRs5JCfDTvMrl4K26vbE,12633
3
+ service_forge/service_config.py,sha256=zsTdCZ1peMAotjGEVypPos7d-gjwrYoB9x_12g95G4g,1242
4
+ service_forge/api/deprecated_websocket_api.py,sha256=E36-fpUPxzMJ2YGlCPeqwRbryk2FMMbQD_pbb8k1FYI,3343
5
+ service_forge/api/deprecated_websocket_manager.py,sha256=Xiwg3zwXRVi63sXmVH-TgbpL2XH_djyLeo96STm4cNM,16757
6
+ service_forge/api/http_api.py,sha256=XnEQ45zuWQV1zrSL9vd3USUh47ymkVc4w_1SoFlNdl8,5648
7
+ service_forge/api/http_api_doc.py,sha256=ASlxvsIiUzDcMhVoumRjt9CfEMbh0O1U4ZLC9eobLF8,20235
8
+ service_forge/api/kafka_api.py,sha256=PInx2ZzKJRON7EaJFWroXkiOt_UeZY7WE6qK03gq4ak,4599
9
+ service_forge/api/task_manager.py,sha256=9Lk-NV4cBnuv9b8V6GVLWJJ4MCiAwCp5TVAwmYgqXbs,5269
10
+ service_forge/api/routers/feedback/feedback_router.py,sha256=JOJI6kaQYapg4__iA6Eo26_9su48p7R2Kpn422nbsxw,5640
11
+ service_forge/api/routers/service/service_router.py,sha256=hGOT-ScnXR7agHp-F9OFGWiPFjG9f3gl7NBsnayW3JI,5088
12
+ service_forge/api/routers/websocket/websocket_manager.py,sha256=j1AFqzXQhZZyaLQwhvZefXAS-zCOPzLcRMDEuusv6V0,3605
13
+ service_forge/api/routers/websocket/websocket_router.py,sha256=V0B7eQP8toO94-WbTrGraadXD3qeZ9lnKFcxwx6kLgM,3777
14
+ service_forge/db/__init__.py,sha256=EWLhH8bYsMOvRF_YXF6FgL3irKA6GZeLxSGvWDRM6f8,85
15
+ service_forge/db/database.py,sha256=IdF7RV-bOFmPPu7d4sQFtsF3e8mZKwMXUkMi7HPEPnc,9329
16
+ service_forge/db/migrations/feedback_migration.py,sha256=-zQ71TsOlWmQPQo1NKSIu3C1T47v3cfD6IAQ5HE_ffk,4845
17
+ service_forge/db/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ service_forge/db/models/feedback.py,sha256=gltX3y-nNhXSR9z1cd82Vg-zwjF0JhnGbOvUapkcWKQ,1253
19
+ service_forge/llm/__init__.py,sha256=x8--4XWqhCVR5n7U3iMvrL16mv-Altb_JgF4qdxSOGk,3170
20
+ service_forge/llm/llm.py,sha256=Sar99FkTPBJqkB6dwX81ww_hJp8cPYxlg7Go-zXPyg0,1865
21
+ service_forge/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ service_forge/model/feedback.py,sha256=Is5tkplzYkjChGb67o-Qjtbu4kSspVuaKi4Aua_QdRo,1318
23
+ service_forge/model/websocket.py,sha256=YIUCW32sbHIEFPHjk5FiDM_rDe2aVD6OpzBQul2R5IM,267
24
+ service_forge/proto/foo_input.py,sha256=-POJZSIFrGdBGz7FqZZ03r5uztpc5Apin9A0Yxbk6YI,90
25
+ service_forge/sft/cli.py,sha256=stB_YPhZ7gAQeOxIq03-tLyl5VfU-gnRacAT05GSMis,2904
26
+ service_forge/sft/cmd/config_command.py,sha256=I9t2HG28S6lCXpExHyZUc47b_1yB3i51tCFVk5J6TTU,2382
27
+ service_forge/sft/cmd/deploy_service.py,sha256=5IYbCVI0Nlry1KXBhm9leJmr2bzUEXrSY-2BympLR0c,4686
28
+ service_forge/sft/cmd/list_tars.py,sha256=Z3zvu2JLb_wNbTwi5TZXL5cZ8PxYrKks9AxkOzoUd_Q,1380
29
+ service_forge/sft/cmd/service_command.py,sha256=69GMMN61KtuoEFuYzFJ74ivNt8RX8q0I6rbePfJfEwQ,5538
30
+ service_forge/sft/cmd/upload_service.py,sha256=86PvvJSXCZKH4BU6rLytuc45grX-sRnQnOHCo9zUaPY,1232
31
+ service_forge/sft/config/injector.py,sha256=El8U5USveKfC0-jhhqYgaevjp4R4fwW02oMvDn7Amyk,5762
32
+ service_forge/sft/config/injector_default_files.py,sha256=aTMQ2Tla3wdpvdaD_5VP2X6oeZbI0X414FM9NbirnO4,2716
33
+ service_forge/sft/config/sf_metadata.py,sha256=Y9akhSCgOd11-oqRs3LIs8FL9pvWNw6hyy57fuFcBhc,866
34
+ service_forge/sft/config/sft_config.py,sha256=MgurtgbcSmyXbGlVX3NG84KD4Hst1gZWHdF9a8zi-6U,7707
35
+ service_forge/sft/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ service_forge/sft/file/ignore_pattern.py,sha256=UrVmR83wOx51XHFcZDTPp15dGYcvMTE5W1m07-SvHpw,2521
37
+ service_forge/sft/file/sft_file_manager.py,sha256=poIM77tZZg7vfwBdCsdQctBbCczVLQePdTwVINEABvE,4337
38
+ service_forge/sft/kubernetes/kubernetes_manager.py,sha256=IF2_X9U-k5Dx7EZuGrJ9lZ85ltbilrrZDfsl8qFyTu4,11339
39
+ service_forge/sft/util/assert_util.py,sha256=8HreVkOzs9_ClKiFqG4qsFn_yyDLo5uXYhYUPXlmDjM,828
40
+ service_forge/sft/util/logger.py,sha256=0Hi74IoxshE-wBgvBa2EZPXYj37tTrUYwlOBd9UMMMs,502
41
+ service_forge/sft/util/name_util.py,sha256=WSYHM6c7SZULXCFON7nmGqsvAPPs_wavd6QjCa4UbRQ,301
42
+ service_forge/sft/util/yaml_utils.py,sha256=9OhJNQlzj_C1NeQoUZVF8qpDovrE7RDWtNXe-H7tuNA,1703
43
+ service_forge/storage/__init__.py,sha256=8Jg4R9z2JHadheV1YrHtCsFxEL5aCl9n2dMQGHcJfvM,156
44
+ service_forge/storage/feedback_storage.py,sha256=wnuNTmEzpnS7iisiU9MrEJIgVa2G_HysqICWk_PxzfU,9124
45
+ service_forge/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ service_forge/utils/default_type_converter.py,sha256=CuUZpMATdTwgcV1M3lbK64znwmEG85Zt3y_QGXr9tYQ,625
47
+ service_forge/utils/register.py,sha256=nxiGQBCX238FoZZhsDoDdBMv_2QzeIZpM367HPNfaqM,874
48
+ service_forge/utils/type_converter.py,sha256=IRphYxyGA0ICwFvDMvqAnRnSUTpY2ZQXvTE5o99CKpo,3046
49
+ service_forge/utils/workflow_clone.py,sha256=I3qNmJLbhAbKb-5VITls89pMmGcWNtI64IOTxN-PUwY,4549
50
+ service_forge/workflow/__init__.py,sha256=9oh4qPyA33RugrUYRAlLmFtmQPUN2wxruFQE3omTJF8,49
51
+ service_forge/workflow/context.py,sha256=1PotSEN_l8Emd5p8_6mtXJngXGYd3NSbOs1EKHgvnlo,346
52
+ service_forge/workflow/edge.py,sha256=88Ex-9_dHAGD38OHgiqP0DrfxK0FrhvDAxThR3ilUi4,627
53
+ service_forge/workflow/node.py,sha256=jPzXuixmZBL6-_jjXikFZmierlu3SOBJOSdQxTyV0FY,7536
54
+ service_forge/workflow/port.py,sha256=JVj0JrnQeOWCsp7n48Cm03bfmO8r3V5oTSEsC-HTGPE,2967
55
+ service_forge/workflow/trigger.py,sha256=2OqiHi0dFcoC8g5GDqVpVEpHKlmqtDADb74Z7PRzHlo,879
56
+ service_forge/workflow/workflow.py,sha256=ykPZBN0sLrORnM83AErcLmFTdUjF5gvbNuMAnY_-p00,8332
57
+ service_forge/workflow/workflow_callback.py,sha256=S__F7s-7l5LgkIXcZMcG68qCyc8NgdWQX81F0hKWL1U,5135
58
+ service_forge/workflow/workflow_config.py,sha256=Yih10b-utKIpaR-X-nfy7fPnmBNhRvlD8Bw2_mQ5lJI,1821
59
+ service_forge/workflow/workflow_event.py,sha256=QG1VFJwUUF1bTKKPKvqBICnYxkBwpfYDEoAuxwQYhhE,371
60
+ service_forge/workflow/workflow_factory.py,sha256=AV39dK2QmG1ed9Mm3BXGI3s-w-o3PuMnwU-Y6VyAVFk,9885
61
+ service_forge/workflow/workflow_group.py,sha256=c-Hcfb-nVKxCVddoEQNFV6nY4LVAku0iq7tTUef9fDM,2076
62
+ service_forge/workflow/workflow_type.py,sha256=zRc-gL2LBE-gOgTUCU5-VDWeGUzuQahkHIg98ipEvQg,1629
63
+ service_forge/workflow/nodes/__init__.py,sha256=AUOoFUAMgRwfLiHNkjnDnWToMSe2AeV5vJO3NCG1eLw,381
64
+ service_forge/workflow/nodes/control/if_node.py,sha256=fBRnSsz0SHW5Hcf4993Y1PsUOUt2Cg9I_zcduHUnMuI,643
65
+ service_forge/workflow/nodes/control/switch_node.py,sha256=27mxdcQijSawNM5Fx6LdC1MB66vAoLAAI74DQyfqPqI,708
66
+ service_forge/workflow/nodes/input/console_input_node.py,sha256=GhQjWRgYy3aRfYUfaEql-_Xi10cca75oz-vmSZkR54w,683
67
+ service_forge/workflow/nodes/llm/query_llm_node.py,sha256=rFSHsPsW2V-yhHSmjx60DcokKy5fdGhNNbt8GIgEIbk,1143
68
+ service_forge/workflow/nodes/nested/workflow_node.py,sha256=h5NXhRCUGaoNmqMV2PXR6JNwTCM8MCRVA6ocOjoDzhs,747
69
+ service_forge/workflow/nodes/output/kafka_output_node.py,sha256=mC6qRMGsuwU6qXAfXA-0ZFZudrlwmgRYOJRULUrtH40,682
70
+ service_forge/workflow/nodes/output/print_node.py,sha256=OSgeRQOd3dq88a1plx30g9-VB793RbXnIa5X8MF9fCo,656
71
+ service_forge/workflow/nodes/test/if_console_input_node.py,sha256=CtKHkFqr8PN974_iGP2VSBmNpXZ-KumRHCpoRR5RyF8,956
72
+ service_forge/workflow/nodes/test/time_consuming_node.py,sha256=gB2qw2DdjRf82z1158u36nSnCHrheHaxscAzPRnXNyk,1813
73
+ service_forge/workflow/triggers/__init__.py,sha256=iQ0WEYu6JgL191Y9XslMhZ7jS7JO8bL3SZ9YqIw5LCM,269
74
+ service_forge/workflow/triggers/a2a_api_trigger.py,sha256=Oaw3vRLA8fWZUIQ-h33dYmojmjp4mwNF_0LHqQ_4mZQ,8583
75
+ service_forge/workflow/triggers/fast_api_trigger.py,sha256=8BF0A8gdcKeiP3cyF_dF0T3MH7bXnnZRCa_h5hx9kQ4,7513
76
+ service_forge/workflow/triggers/kafka_api_trigger.py,sha256=Zv8J75Rmg1-xqxHwpBMBhsm_TWX8p3_rqldk2RVSwVc,1561
77
+ service_forge/workflow/triggers/once_trigger.py,sha256=YmzSQBoKE-8liNFIoDCqi2UdqhHujizsXVDft81_8jA,572
78
+ service_forge/workflow/triggers/period_trigger.py,sha256=JFX3yBjKqoRP55jiulaSG_SPO-zWLMcwEb1BwcKsWUM,767
79
+ service_forge/workflow/triggers/websocket_api_trigger.py,sha256=DRVFVdR3NgUx8S6Rlv492_3xrmlNGDOcvUrz13jHQ7o,6902
80
+ service_forge-0.1.18.dist-info/METADATA,sha256=dP-GKlnX6P32jvP-1oudgM_Rj760sCCf6fayQf9FvuY,2308
81
+ service_forge-0.1.18.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
82
+ service_forge-0.1.18.dist-info/entry_points.txt,sha256=WHntHW7GAyKQUEeMcMvHDZ7_xAb0-cZeAK4iJeu9lm8,51
83
+ service_forge-0.1.18.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sft = service_forge.sft.cli:main