interlace-py 0.2.0__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 (72) hide show
  1. interlace_py-0.2.0/.gitignore +50 -0
  2. interlace_py-0.2.0/LICENSE +21 -0
  3. interlace_py-0.2.0/PKG-INFO +170 -0
  4. interlace_py-0.2.0/README.md +142 -0
  5. interlace_py-0.2.0/docs/01-design-philosophy.md +128 -0
  6. interlace_py-0.2.0/docs/02-first-graph.md +76 -0
  7. interlace_py-0.2.0/docs/03-graph-dataflow.md +213 -0
  8. interlace_py-0.2.0/docs/04-events-and-workflows.md +159 -0
  9. interlace_py-0.2.0/docs/05-execution.md +370 -0
  10. interlace_py-0.2.0/docs/06-runtime-architecture.md +284 -0
  11. interlace_py-0.2.0/docs/07-plugins.md +661 -0
  12. interlace_py-0.2.0/docs/08-patterns.md +178 -0
  13. interlace_py-0.2.0/docs/09-service.md +295 -0
  14. interlace_py-0.2.0/docs/README.md +58 -0
  15. interlace_py-0.2.0/examples/__init__.py +1 -0
  16. interlace_py-0.2.0/examples/async_node.py +54 -0
  17. interlace_py-0.2.0/examples/cycle.py +59 -0
  18. interlace_py-0.2.0/examples/domain_context.py +147 -0
  19. interlace_py-0.2.0/examples/event_routing.py +91 -0
  20. interlace_py-0.2.0/examples/fan_in.py +83 -0
  21. interlace_py-0.2.0/examples/linear.py +81 -0
  22. interlace_py-0.2.0/examples/output_stream.py +96 -0
  23. interlace_py-0.2.0/examples/service.py +132 -0
  24. interlace_py-0.2.0/interlace/__init__.py +13 -0
  25. interlace_py-0.2.0/interlace/_validation.py +69 -0
  26. interlace_py-0.2.0/interlace/adapters/__init__.py +5 -0
  27. interlace_py-0.2.0/interlace/adapters/memory.py +791 -0
  28. interlace_py-0.2.0/interlace/engine/__init__.py +21 -0
  29. interlace_py-0.2.0/interlace/engine/core.py +239 -0
  30. interlace_py-0.2.0/interlace/engine/errors.py +147 -0
  31. interlace_py-0.2.0/interlace/engine/events.py +370 -0
  32. interlace_py-0.2.0/interlace/engine/execution.py +957 -0
  33. interlace_py-0.2.0/interlace/engine/execution_resources.py +168 -0
  34. interlace_py-0.2.0/interlace/engine/executor.py +1103 -0
  35. interlace_py-0.2.0/interlace/engine/extension.py +611 -0
  36. interlace_py-0.2.0/interlace/engine/graph.py +889 -0
  37. interlace_py-0.2.0/interlace/engine/hooks.py +133 -0
  38. interlace_py-0.2.0/interlace/engine/observation.py +118 -0
  39. interlace_py-0.2.0/interlace/engine/options.py +32 -0
  40. interlace_py-0.2.0/interlace/engine/points.py +35 -0
  41. interlace_py-0.2.0/interlace/engine/policies.py +179 -0
  42. interlace_py-0.2.0/interlace/engine/runner.py +193 -0
  43. interlace_py-0.2.0/interlace/engine/slots.py +451 -0
  44. interlace_py-0.2.0/interlace/nodes/__init__.py +5 -0
  45. interlace_py-0.2.0/interlace/nodes/keyed_join.py +142 -0
  46. interlace_py-0.2.0/interlace/plugins/__init__.py +50 -0
  47. interlace_py-0.2.0/interlace/plugins/background.py +115 -0
  48. interlace_py-0.2.0/interlace/plugins/host.py +874 -0
  49. interlace_py-0.2.0/interlace/plugins/points.py +92 -0
  50. interlace_py-0.2.0/interlace/plugins/settings.py +213 -0
  51. interlace_py-0.2.0/interlace/py.typed +1 -0
  52. interlace_py-0.2.0/interlace/runtime/__init__.py +14 -0
  53. interlace_py-0.2.0/interlace/runtime/_utils.py +132 -0
  54. interlace_py-0.2.0/interlace/runtime/direct.py +61 -0
  55. interlace_py-0.2.0/interlace/runtime/facade.py +680 -0
  56. interlace_py-0.2.0/interlace/runtime/history.py +148 -0
  57. interlace_py-0.2.0/interlace/runtime/plugin.py +305 -0
  58. interlace_py-0.2.0/interlace/runtime/router.py +447 -0
  59. interlace_py-0.2.0/interlace/runtime/worker.py +980 -0
  60. interlace_py-0.2.0/interlace/service/__init__.py +7 -0
  61. interlace_py-0.2.0/interlace/service/catalog.py +217 -0
  62. interlace_py-0.2.0/interlace/service/diagnostics.py +428 -0
  63. interlace_py-0.2.0/interlace/service/errors.py +31 -0
  64. interlace_py-0.2.0/interlace/service/http.py +689 -0
  65. interlace_py-0.2.0/interlace/service/models.py +135 -0
  66. interlace_py-0.2.0/interlace/service/service.py +1069 -0
  67. interlace_py-0.2.0/interlace/service/store.py +832 -0
  68. interlace_py-0.2.0/interlace/spi/__init__.py +57 -0
  69. interlace_py-0.2.0/interlace/spi/roles.py +298 -0
  70. interlace_py-0.2.0/interlace/spi/runtime.py +369 -0
  71. interlace_py-0.2.0/pyproject.toml +66 -0
  72. interlace_py-0.2.0/tests/examples/test_patterns.py +51 -0
@@ -0,0 +1,50 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg-info/
7
+ *.egg
8
+ dist/
9
+ build/
10
+ eggs/
11
+ *.whl
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ ENV/
17
+
18
+ # IDE
19
+ .idea/
20
+ .vscode/
21
+ *.swp
22
+ *.swo
23
+ *~
24
+
25
+ # OS
26
+ .DS_Store
27
+ Thumbs.db
28
+ desktop.ini
29
+
30
+ # Environment
31
+ .env
32
+ .env.local
33
+ .env.*.local
34
+
35
+ # Logs
36
+ *.log
37
+ logs/
38
+
39
+ # Database
40
+ *.db
41
+ *.sqlite3
42
+
43
+ # uv
44
+ .python-version
45
+
46
+ # Project specific
47
+ .pytest_cache/
48
+ .mypy_cache/
49
+ .ruff_cache/
50
+ .interlace/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Kem
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.5
2
+ Name: interlace-py
3
+ Version: 0.2.0
4
+ Summary: An extensible microkernel for typed graphs and event workflows
5
+ Project-URL: Homepage, https://github.com/KKKKKKKEM/interlace
6
+ Project-URL: Repository, https://github.com/KKKKKKKEM/interlace.git
7
+ Author-email: Kem <531144129@qq.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: automation,engine,graph,state-machine,workflow
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: <3.15,>=3.10
22
+ Provides-Extra: service
23
+ Requires-Dist: fastapi<1,>=0.115; extra == 'service'
24
+ Requires-Dist: jsonrpcserver<6,>=5; extra == 'service'
25
+ Requires-Dist: pydantic<3,>=2.9; extra == 'service'
26
+ Requires-Dist: uvicorn<1,>=0.30; extra == 'service'
27
+ Description-Content-Type: text/markdown
28
+
29
+ # Interlace
30
+
31
+ Interlace 是一个可扩展的 Python 编排微内核:Graph 内以 `Output` 和 `Edge` 传递局部数据,Graph 间以
32
+ `Event` 和 `Runtime` 连接领域工作流。
33
+
34
+ 核心实现通过公开协议替换,功能通过插件和领域节点扩展,Graph 与 Execution 的公共契约保持稳定。
35
+ 运行时没有第三方依赖;爬虫模型、下载器与下载节点由独立的 [Bricks](https://github.com/KKKKKKKEM/bricks) 提供。
36
+
37
+ ## 安装
38
+
39
+ 发行包名为 `interlace-py`,导入名为 `interlace`。当前通过 Git 安装,尚未发布到 PyPI:
40
+
41
+ ```bash
42
+ uv pip install "interlace-py @ git+https://github.com/KKKKKKKEM/interlace.git"
43
+ ```
44
+
45
+ 生产项目应将 Git 依赖固定到经过验证的提交。开发本仓库可使用 `uv sync`。
46
+
47
+ ### 发布到 PyPI
48
+
49
+ 仓库的 `.github/workflows/python-publish.yml` 在 GitHub Release 发布后运行完整 CI、构建 wheel/sdist、
50
+ 检查发行元数据,并通过 PyPI Trusted Publishing 上传同一批已验证产物。Release 标签必须与项目版本一致:
51
+ 当前版本为 `0.2.0`,对应标签 `v0.2.0`。尚未完成首次上传,不能把上述 Git 安装命令改成索引安装。
52
+
53
+ 首次发布前,在 PyPI 的 Publishing 页面添加 pending publisher:
54
+
55
+ - PyPI 项目:`interlace-py`(`interlace` 在 PyPI 禁用名单中)
56
+ - GitHub owner:`KKKKKKKEM`
57
+ - GitHub repository:`interlace`
58
+ - Workflow filename:`python-publish.yml`
59
+ - Environment:`pypi`
60
+
61
+ 发布工作流只在上传作业授予 OIDC `id-token: write`,不借用其他仓库的 PyPI Token。
62
+ 维护者应在 GitHub 配置 `pypi` environment 的审批与标签限制,再发布对应 Release。
63
+ 上传成功后先确认 PyPI 可安装该版本,再让下游更新依赖与锁文件;不要用本地目录替换下游正式依赖。
64
+
65
+ 本地检查发行包:
66
+
67
+ ```bash
68
+ uv build --no-sources
69
+ uv tool run twine check --strict dist/*
70
+ ```
71
+
72
+ 构建与元数据检查通过不代表已经上传,也不代表 PyPI 已授予项目发布权限。
73
+
74
+ ```text
75
+ Node -- Output / Edge --> Node
76
+ Graph -- Event / Runtime --> Graph
77
+ ```
78
+
79
+ 顶层 API 还提供进程内的 `Slot` 与 `SlotPool`:队列 Work 可以在同一进程中跨 Consumer 传递并复用代理、Cookie、
80
+ 连接等执行状态,而不依赖具体线程。Slot 不跨进程或消息边界传输。
81
+
82
+ 执行默认不限步数、时长和 Graph 内积压;`run()`、`start()` 和事件 route 可按需设置 `max_steps`、Graph `timeout`
83
+ 与待消费输入上限 `max_queued`,单次 Node firing 的时限由该 Node 的 `timeout` 属性声明。`start()` 返回可查询和
84
+ 协作式取消的 `Execution`。
85
+ `Execution` 可调用 `result()`、直接 `await`,也可同步或异步迭代 terminal Output;`Runtime.iter()` 和
86
+ `Runtime.aiter()` 提供对应便利入口。
87
+
88
+ 所有节点统一继承 `Node`。`execute()` 可以使用普通 `def` 或 `async def`;普通函数返回的 Awaitable 也由
89
+ Engine 等待,再按相同的 Output 契约处理结果。
90
+
91
+ ## 最小示例
92
+
93
+ ```python
94
+ from interlace import Graph, Node, Output, Runtime
95
+
96
+
97
+ class Upper(Node):
98
+ inputs = {"text": str}
99
+ outputs = {"result": str}
100
+ timeout = 5
101
+
102
+ def execute(self, inputs, context):
103
+ del context
104
+ return Output(inputs["text"].upper(), "result")
105
+
106
+
107
+ graph = Graph.compose(nodes={"upper": Upper()}, entrypoint="upper")
108
+
109
+ with Runtime() as runtime:
110
+ runtime.register("upper.graph", graph)
111
+ print(runtime.run("upper.graph", "interlace"))
112
+ ```
113
+
114
+ 完整内容按一本手册组织,从[文档目录](https://github.com/KKKKKKKEM/interlace/blob/main/docs/README.md)开始:
115
+
116
+ 1. [设计哲学与心智模型](https://github.com/KKKKKKKEM/interlace/blob/main/docs/01-design-philosophy.md)
117
+ 2. [第一张 Graph](https://github.com/KKKKKKKEM/interlace/blob/main/docs/02-first-graph.md)
118
+ 3. [Graph 数据流](https://github.com/KKKKKKKEM/interlace/blob/main/docs/03-graph-dataflow.md)
119
+ 4. [Event 与跨图工作流](https://github.com/KKKKKKKEM/interlace/blob/main/docs/04-events-and-workflows.md)
120
+ 5. [Execution、并发与失败](https://github.com/KKKKKKKEM/interlace/blob/main/docs/05-execution.md)
121
+ 6. [Runtime 内部架构](https://github.com/KKKKKKKEM/interlace/blob/main/docs/06-runtime-architecture.md)
122
+ 7. [插件、SPI 与适配器开发](https://github.com/KKKKKKKEM/interlace/blob/main/docs/07-plugins.md)
123
+ 8. [编排模式](https://github.com/KKKKKKKEM/interlace/blob/main/docs/08-patterns.md)
124
+ 9. [RPC 与图服务](https://github.com/KKKKKKKEM/interlace/blob/main/docs/09-service.md)
125
+
126
+ ## 可选 RPC 与图服务
127
+
128
+ 官方服务 extra 提供 HTTP/JSON 调用、JSON-RPC 2.0、SSE 输出流,以及图编辑发布、项目管理与运行历史接口。
129
+ 服务只提供数据接口,不托管前端页面;基础安装仍保持零运行时依赖,不自动启动服务。
130
+
131
+ ```bash
132
+ uv pip install "interlace-py[service] @ git+https://github.com/KKKKKKKEM/interlace.git"
133
+ uv run --extra service python examples/service.py
134
+ ```
135
+
136
+ 启动后在 `http://127.0.0.1:8000/docs` 查看 OpenAPI 文档。已有代码图直接支持远程调用和运行查看;登记节点工厂与
137
+ 配置模型后,还可以通过编辑文档校验、保存草稿与发布不可变版本。
138
+
139
+ 已有 Runtime 可直接接入:
140
+
141
+ ```python
142
+ from interlace.service import GraphService
143
+
144
+ # runtime 为已经注册 Graph 的运行时,由调用方管理生命周期。
145
+ service = GraphService(runtime, database=".interlace/service.sqlite3")
146
+ service.serve()
147
+ ```
148
+
149
+ 安装、节点目录、HTTP/JSON-RPC 调用及服务所有权见[第九章](https://github.com/KKKKKKKEM/interlace/blob/main/docs/09-service.md)。
150
+
151
+ ## 当前范围
152
+
153
+ 默认实现通过内建 `LocalRuntimePlugin` 提供内存事件分发、线程池队列并发和 Graph 执行;它与第三方扩展一样由
154
+ 统一 `PluginHost` 装配。EventBus、任务传输、GraphExecutor、输入策略、Node Hook 和 Runtime Observer 均可受控
155
+ 扩展,但 Graph 的类型、冻结和 Execution 语义保持固定。默认实现不提供持久化、broker ack、进程恢复、定时器、
156
+ 死信队列或 exactly-once 语义。
157
+
158
+ 源码按 `engine`、`runtime`、`plugins`、`spi`、`adapters` 和可复用 `nodes` 分层;各包职责、目录树和允许的
159
+ 依赖方向见[Runtime 内部架构](https://github.com/KKKKKKKEM/interlace/blob/main/docs/06-runtime-architecture.md#源码目录与包职责)。
160
+
161
+ ```bash
162
+ uv run python examples/linear.py
163
+ uv run python examples/fan_in.py
164
+ uv run python examples/cycle.py
165
+ uv run python examples/event_routing.py
166
+ uv run python examples/async_node.py
167
+ uv run python examples/output_stream.py
168
+ uv run python examples/domain_context.py
169
+ uv run pytest -q
170
+ ```
@@ -0,0 +1,142 @@
1
+ # Interlace
2
+
3
+ Interlace 是一个可扩展的 Python 编排微内核:Graph 内以 `Output` 和 `Edge` 传递局部数据,Graph 间以
4
+ `Event` 和 `Runtime` 连接领域工作流。
5
+
6
+ 核心实现通过公开协议替换,功能通过插件和领域节点扩展,Graph 与 Execution 的公共契约保持稳定。
7
+ 运行时没有第三方依赖;爬虫模型、下载器与下载节点由独立的 [Bricks](https://github.com/KKKKKKKEM/bricks) 提供。
8
+
9
+ ## 安装
10
+
11
+ 发行包名为 `interlace-py`,导入名为 `interlace`。当前通过 Git 安装,尚未发布到 PyPI:
12
+
13
+ ```bash
14
+ uv pip install "interlace-py @ git+https://github.com/KKKKKKKEM/interlace.git"
15
+ ```
16
+
17
+ 生产项目应将 Git 依赖固定到经过验证的提交。开发本仓库可使用 `uv sync`。
18
+
19
+ ### 发布到 PyPI
20
+
21
+ 仓库的 `.github/workflows/python-publish.yml` 在 GitHub Release 发布后运行完整 CI、构建 wheel/sdist、
22
+ 检查发行元数据,并通过 PyPI Trusted Publishing 上传同一批已验证产物。Release 标签必须与项目版本一致:
23
+ 当前版本为 `0.2.0`,对应标签 `v0.2.0`。尚未完成首次上传,不能把上述 Git 安装命令改成索引安装。
24
+
25
+ 首次发布前,在 PyPI 的 Publishing 页面添加 pending publisher:
26
+
27
+ - PyPI 项目:`interlace-py`(`interlace` 在 PyPI 禁用名单中)
28
+ - GitHub owner:`KKKKKKKEM`
29
+ - GitHub repository:`interlace`
30
+ - Workflow filename:`python-publish.yml`
31
+ - Environment:`pypi`
32
+
33
+ 发布工作流只在上传作业授予 OIDC `id-token: write`,不借用其他仓库的 PyPI Token。
34
+ 维护者应在 GitHub 配置 `pypi` environment 的审批与标签限制,再发布对应 Release。
35
+ 上传成功后先确认 PyPI 可安装该版本,再让下游更新依赖与锁文件;不要用本地目录替换下游正式依赖。
36
+
37
+ 本地检查发行包:
38
+
39
+ ```bash
40
+ uv build --no-sources
41
+ uv tool run twine check --strict dist/*
42
+ ```
43
+
44
+ 构建与元数据检查通过不代表已经上传,也不代表 PyPI 已授予项目发布权限。
45
+
46
+ ```text
47
+ Node -- Output / Edge --> Node
48
+ Graph -- Event / Runtime --> Graph
49
+ ```
50
+
51
+ 顶层 API 还提供进程内的 `Slot` 与 `SlotPool`:队列 Work 可以在同一进程中跨 Consumer 传递并复用代理、Cookie、
52
+ 连接等执行状态,而不依赖具体线程。Slot 不跨进程或消息边界传输。
53
+
54
+ 执行默认不限步数、时长和 Graph 内积压;`run()`、`start()` 和事件 route 可按需设置 `max_steps`、Graph `timeout`
55
+ 与待消费输入上限 `max_queued`,单次 Node firing 的时限由该 Node 的 `timeout` 属性声明。`start()` 返回可查询和
56
+ 协作式取消的 `Execution`。
57
+ `Execution` 可调用 `result()`、直接 `await`,也可同步或异步迭代 terminal Output;`Runtime.iter()` 和
58
+ `Runtime.aiter()` 提供对应便利入口。
59
+
60
+ 所有节点统一继承 `Node`。`execute()` 可以使用普通 `def` 或 `async def`;普通函数返回的 Awaitable 也由
61
+ Engine 等待,再按相同的 Output 契约处理结果。
62
+
63
+ ## 最小示例
64
+
65
+ ```python
66
+ from interlace import Graph, Node, Output, Runtime
67
+
68
+
69
+ class Upper(Node):
70
+ inputs = {"text": str}
71
+ outputs = {"result": str}
72
+ timeout = 5
73
+
74
+ def execute(self, inputs, context):
75
+ del context
76
+ return Output(inputs["text"].upper(), "result")
77
+
78
+
79
+ graph = Graph.compose(nodes={"upper": Upper()}, entrypoint="upper")
80
+
81
+ with Runtime() as runtime:
82
+ runtime.register("upper.graph", graph)
83
+ print(runtime.run("upper.graph", "interlace"))
84
+ ```
85
+
86
+ 完整内容按一本手册组织,从[文档目录](https://github.com/KKKKKKKEM/interlace/blob/main/docs/README.md)开始:
87
+
88
+ 1. [设计哲学与心智模型](https://github.com/KKKKKKKEM/interlace/blob/main/docs/01-design-philosophy.md)
89
+ 2. [第一张 Graph](https://github.com/KKKKKKKEM/interlace/blob/main/docs/02-first-graph.md)
90
+ 3. [Graph 数据流](https://github.com/KKKKKKKEM/interlace/blob/main/docs/03-graph-dataflow.md)
91
+ 4. [Event 与跨图工作流](https://github.com/KKKKKKKEM/interlace/blob/main/docs/04-events-and-workflows.md)
92
+ 5. [Execution、并发与失败](https://github.com/KKKKKKKEM/interlace/blob/main/docs/05-execution.md)
93
+ 6. [Runtime 内部架构](https://github.com/KKKKKKKEM/interlace/blob/main/docs/06-runtime-architecture.md)
94
+ 7. [插件、SPI 与适配器开发](https://github.com/KKKKKKKEM/interlace/blob/main/docs/07-plugins.md)
95
+ 8. [编排模式](https://github.com/KKKKKKKEM/interlace/blob/main/docs/08-patterns.md)
96
+ 9. [RPC 与图服务](https://github.com/KKKKKKKEM/interlace/blob/main/docs/09-service.md)
97
+
98
+ ## 可选 RPC 与图服务
99
+
100
+ 官方服务 extra 提供 HTTP/JSON 调用、JSON-RPC 2.0、SSE 输出流,以及图编辑发布、项目管理与运行历史接口。
101
+ 服务只提供数据接口,不托管前端页面;基础安装仍保持零运行时依赖,不自动启动服务。
102
+
103
+ ```bash
104
+ uv pip install "interlace-py[service] @ git+https://github.com/KKKKKKKEM/interlace.git"
105
+ uv run --extra service python examples/service.py
106
+ ```
107
+
108
+ 启动后在 `http://127.0.0.1:8000/docs` 查看 OpenAPI 文档。已有代码图直接支持远程调用和运行查看;登记节点工厂与
109
+ 配置模型后,还可以通过编辑文档校验、保存草稿与发布不可变版本。
110
+
111
+ 已有 Runtime 可直接接入:
112
+
113
+ ```python
114
+ from interlace.service import GraphService
115
+
116
+ # runtime 为已经注册 Graph 的运行时,由调用方管理生命周期。
117
+ service = GraphService(runtime, database=".interlace/service.sqlite3")
118
+ service.serve()
119
+ ```
120
+
121
+ 安装、节点目录、HTTP/JSON-RPC 调用及服务所有权见[第九章](https://github.com/KKKKKKKEM/interlace/blob/main/docs/09-service.md)。
122
+
123
+ ## 当前范围
124
+
125
+ 默认实现通过内建 `LocalRuntimePlugin` 提供内存事件分发、线程池队列并发和 Graph 执行;它与第三方扩展一样由
126
+ 统一 `PluginHost` 装配。EventBus、任务传输、GraphExecutor、输入策略、Node Hook 和 Runtime Observer 均可受控
127
+ 扩展,但 Graph 的类型、冻结和 Execution 语义保持固定。默认实现不提供持久化、broker ack、进程恢复、定时器、
128
+ 死信队列或 exactly-once 语义。
129
+
130
+ 源码按 `engine`、`runtime`、`plugins`、`spi`、`adapters` 和可复用 `nodes` 分层;各包职责、目录树和允许的
131
+ 依赖方向见[Runtime 内部架构](https://github.com/KKKKKKKEM/interlace/blob/main/docs/06-runtime-architecture.md#源码目录与包职责)。
132
+
133
+ ```bash
134
+ uv run python examples/linear.py
135
+ uv run python examples/fan_in.py
136
+ uv run python examples/cycle.py
137
+ uv run python examples/event_routing.py
138
+ uv run python examples/async_node.py
139
+ uv run python examples/output_stream.py
140
+ uv run python examples/domain_context.py
141
+ uv run pytest -q
142
+ ```
@@ -0,0 +1,128 @@
1
+ # 第一章:设计哲学与心智模型
2
+
3
+ 本章先回答两个问题:Interlace 试图解决什么,以及为什么它选择现在这组概念。理解这两个问题后,后续 API 会更容易
4
+ 记忆,因为它们都从同一套边界推导出来。
5
+
6
+ ## 一句话定义
7
+
8
+ Interlace 是一个 typed graph runtime:一张 Graph 描述一次局部计算,多张 Graph 通过领域 Event 连接成工作流。
9
+
10
+ ```mermaid
11
+ flowchart LR
12
+ subgraph Local[Graph 内:静态 typed dataflow]
13
+ A[Node A] -->|Output / Edge| B[Node B]
14
+ B -->|terminal Output| Result[调用方]
15
+ end
16
+
17
+ subgraph Workflow[Graph 间:异步领域工作流]
18
+ G1[Graph A] -->|Event| R[Runtime route]
19
+ R -->|Work| G2[Graph B]
20
+ end
21
+ ```
22
+
23
+ 核心设计原则是:
24
+
25
+ > 内核语义固定,非本质能力可插拔;局部计算用 Graph,跨图协作用 Event。
26
+
27
+ ## 为什么要区分两种流动
28
+
29
+ 数据在同一张 Graph 内流动时,连接关系是静态的,类型可以提前校验,执行过程也可以从图结构推导。这里使用
30
+ `Output` 和 `Edge`。
31
+
32
+ 跨 Graph 协作表达的是领域事实,例如“订单已创建”或“页面已抓取”。它可能启动零个、一个或多个后续工作,部署
33
+ 位置和执行时间也不属于源 Graph。这里使用 `Event`。
34
+
35
+ 两条通路不会隐式转换:
36
+
37
+ - Node 返回的 Output 不会自动发布成 Event;
38
+ - Event payload 不会自动进入某条 Edge;
39
+ - Graph 不直接引用或调用另一张 Graph;
40
+ - 目标 Graph 不在源 Node 的 `emit()` 调用栈中执行。
41
+
42
+ 这个边界让单张 Graph 保持可推理,也让跨 Graph 工作流可以独立扩展和部署。
43
+
44
+ ## 按层暴露的概念
45
+
46
+ 概念是“必须知道才能用”的东西:能做成方法、参数或返回值的,就不要求用户导入一个类名。能力靠组合少数原语获得,
47
+ 不为每个场景新增机制。每一层只比上一层多一两个概念:
48
+
49
+ | 层次 | 读者 | 需要理解的概念 | 其余能力从哪里来 |
50
+ | --- | --- | --- | --- |
51
+ | 写业务 | 所有人 | `Graph`、`Node`、`Output`、`Runtime` | `Context` 作为参数传入,跨图事实经 `context.emit()` 发出 |
52
+ | 编排 | 所有人 | 不新增 | `connect`、`on`、`emit`、`plan()`、`iter()` 与 `options=`、`slots=`、`timeout=` 等参数 |
53
+ | 扩展 | 插件作者 | 钩子点、插件 | 插件是 `setup(api)`,只有 `on`、`provide`、`wrap`、`require`、`defer` 五个动作 |
54
+ | 换基础设施 | 适配器作者 | SPI 协议 | `interlace.spi` 中的窄协议,普通用户看不到 |
55
+
56
+ 顶层 `interlace` 因此只有 `Graph`、`Node`、`Output`、`Runtime`、`Context`、`Event` 六个名字。汇聚策略
57
+ `InputPolicy`、显式连接 `Edge`、执行计划 `ExecutionPlan`、执行句柄 `Execution` 与跨队列共享的 `SlotPool` 位于
58
+ `interlace.engine`,只在需要时导入。
59
+
60
+ ## 微内核:哪些东西不能被插件改变
61
+
62
+ 以下语义共同定义了“什么是 Interlace Graph”,因此属于微内核:
63
+
64
+ - 端口的类型约束;
65
+ - Graph 的冻结、可达性和 Edge 校验;
66
+ - InputPolicy 的 token 消费规则;
67
+ - Output 的局部传播;
68
+ - Event 与 Graph 数据流的边界;
69
+ - Execution 的状态、步数、超时、取消和错误语义。
70
+
71
+ 如果插件可以改写这些规则,同一张 Graph 在不同环境中就可能具有不同含义,静态校验也会失去价值。
72
+ 稳定的是公共契约,不是默认实现。满足相同契约的执行器、Router、Worker、Slot 池、输出存储和通知机制都可以
73
+ 通过公开协议替换;应用仍使用同一套 Graph、Event 和 Execution 模型。
74
+
75
+ ## 可插拔能力:哪些东西允许变化
76
+
77
+ 部署环境和横切能力变化频繁,适合通过窄协议或统一的扩展机制变化:
78
+
79
+ - EventBus 与任务传输;
80
+ - GraphExecutor;
81
+ - RouterRole、WorkerRole 和 SlotProvider;
82
+ - ExecutionFactory、OutputStore 和 ExecutionNotifier;
83
+ - 按名称提供的输入 selector 等具名值;
84
+ - 核心钩子点上的处理函数:事件改写、Work 路由、交付与执行中间件、节点中间件、只读生命周期事实;
85
+ - 插件为领域定义的钩子点,以及领域 Node 和状态适配器。
86
+
87
+ 扩展只有一套机制:两种钩子点(只读 Notice 与中间件 Wrap)加按名称提供、可装饰的具名值,核心与插件以同一方式
88
+ 定义和使用。默认内存实现也由 `LocalInfrastructurePlugin` 与 `LocalRuntimePlugin` 通过 `PluginHost` 安装,与应用插件
89
+ 走同一套依赖、具名值和清理路径。插件只能通过钩子点与具名值扩展,不能访问 Runtime 私有状态或改写微内核规则;
90
+ 钩子点也不能吞掉执行控制异常或产生违反端口契约的结果。
91
+
92
+ ```mermaid
93
+ flowchart TB
94
+ App[应用 Graph 与 Node]
95
+ Contributions[插件:钩子点 / 具名值]
96
+ Kernel[微内核语义]
97
+
98
+ App --> Kernel
99
+ Contributions -->|只能通过 capability| Kernel
100
+
101
+ subgraph Fixed[稳定契约]
102
+ Kernel --> Types[端口 / Edge 类型]
103
+ Kernel --> Freeze[Graph freeze]
104
+ Kernel --> Exec[Execution 状态机]
105
+ Kernel --> Boundary[Output / Event 边界]
106
+ end
107
+ ```
108
+
109
+ ## Less is more
110
+
111
+ 顶层 API 只保留建立和运行工作流所需的对象。Work、Delivery、Router、Worker、Backend 和 PluginHost 虽然在实现中
112
+ 存在,但普通用户不需要逐项组装。
113
+
114
+ 这条原则也决定了框架的失败方式:错误配置应尽早、明确地失败,而不是通过隐式转换、默认重试或兼容分支猜测
115
+ 调用方意图。
116
+
117
+ ## 可靠性边界
118
+
119
+ 默认实现是单进程内存运行时,不宣称持久化、broker ack、跨进程恢复、定时调度、死信队列或 exactly-once。
120
+ 事件被接受后不会因为源 Graph 随后失败而撤回。外部副作用的幂等、领域去重和业务重试应由领域 Graph、Store 或
121
+ 明确声明这些语义的后端实现。
122
+
123
+ ## 接下来怎么读
124
+
125
+ 下一章会运行第一张 Graph。之后分别深入 Graph 内的数据流和 Graph 间的事件流,再讨论 Execution、内部架构与
126
+ 插件开发。
127
+
128
+ [下一章:第一张 Graph](02-first-graph.md)
@@ -0,0 +1,76 @@
1
+ # 第二章:第一张 Graph
2
+
3
+ 上一章建立了 Output、Event 和插件边界的整体模型。本章只做一件事:定义并运行一张最小 Graph。
4
+
5
+ 下面的例子把一个字符串转换为大写。它展示 Interlace 的最小闭环:声明 Node、构建并注册 Graph、再执行它。
6
+
7
+ ```python
8
+ from interlace import Graph, Node, Output, Runtime
9
+
10
+
11
+ class Upper(Node):
12
+ inputs = {"text": str}
13
+ outputs = {"result": str}
14
+ timeout = 5 # None 表示该 Node 的单次执行不限时
15
+
16
+ def execute(self, inputs, context):
17
+ del context
18
+ return Output(inputs["text"].upper(), port="result")
19
+
20
+
21
+ graph = Graph.compose(nodes={"upper": Upper()}, entrypoint="upper")
22
+
23
+ with Runtime() as runtime:
24
+ runtime.register("upper.graph", graph) # register() 会冻结并校验 Graph
25
+ outputs = runtime.run("upper.graph", "interlace")
26
+
27
+ assert outputs == (Output("INTERLACE", port="result"),)
28
+ ```
29
+
30
+ 这段程序经历了一个完整但很短的生命周期:
31
+
32
+ ```mermaid
33
+ flowchart LR
34
+ NodeDef[定义 Upper Node] --> GraphDef[绑定到 Graph]
35
+ GraphDef --> Register[Runtime.register]
36
+ Register --> Freeze[冻结并校验]
37
+ Freeze --> Run[Runtime.run]
38
+ Run --> Execute[Upper.execute]
39
+ Execute --> Output[terminal Output]
40
+ ```
41
+
42
+ 单节点没有下游 Edge,因此它产生的 `Output` 会作为 `Runtime.run()` 的返回值。若把 output port 连接给另一个
43
+ Node,它只在同一张 Graph 内传播。
44
+
45
+ `Graph.compose()` 将节点映射、显式入口和可选的 `edges` 集合集中声明;单节点示例可以省略边。
46
+ 返回的图仍可继续修改,注册时统一冻结校验。多节点组装见下一章的 [Graph 与 Edge](03-graph-dataflow.md#graph-与-edge)。
47
+
48
+ 默认不限制执行步数和时长。需要约束循环或外部调用时,可以显式配置:
49
+
50
+ ```python
51
+ outputs = runtime.run(
52
+ "upper.graph",
53
+ "interlace",
54
+ max_steps=10, # 0 表示无限步
55
+ timeout=30, # None 表示 Graph 总时长不限
56
+ )
57
+ ```
58
+
59
+ ## 运行仓库中的示例
60
+
61
+ 项目没有运行时第三方依赖;使用 uv 可直接执行示例:
62
+
63
+ ```bash
64
+ uv run python examples/linear.py
65
+ uv run python examples/fan_in.py
66
+ uv run python examples/event_routing.py
67
+ uv run python examples/async_node.py
68
+ ```
69
+
70
+ 测试工具位于 `pyproject.toml` 的 `dev` 依赖组,`uv run` 默认同步该组:
71
+
72
+ ```bash
73
+ uv run pytest -q
74
+ ```
75
+
76
+ [上一章:设计哲学与心智模型](01-design-philosophy.md) · [下一章:Graph 数据流](03-graph-dataflow.md)