bazaar-compute-node 0.1.7__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.
- bazaar_compute_node-0.1.9/PKG-INFO +106 -0
- bazaar_compute_node-0.1.9/README.md +93 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/pyproject.toml +3 -2
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/pyproject.toml.orig +3 -2
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/application.py +43 -16
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/command.py +33 -11
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/config.py +14 -10
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/registry.py +24 -7
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/app/reminder_dispatch.py +411 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/bcc.py +913 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/cli.py +2 -5
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/codex/approval.py +50 -3
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/sqlite/__init__.py +2 -1
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/sqlite/plugin.py +1 -1
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/sqlite/reminder_codec.py +63 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/sqlite/reminder_database.py +21 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/sqlite/reminder_migration.py +85 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/sqlite/reminder_repository.py +420 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/__init__.py +1 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/api.py +356 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/approval.py +411 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/attachments.py +442 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/channel.py +846 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/identity.py +68 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/markdown.py +343 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/outbound.py +796 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/telegram/plugin.py +20 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/wecom/channel.py +10 -5
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/contrib/wecom/plugin.py +33 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/channel.py +50 -5
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/command.py +54 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/instruction.py +46 -10
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/models/__init__.py +7 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/models/entities.py +3 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/core/models/reminder.py +282 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/models/states.py +13 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/orchestration/__init__.py +2 -1
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/core/orchestration/reminder.py +250 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/core/orchestration/reminder_command.py +362 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/orchestration/session.py +182 -59
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/orchestration/turn.py +40 -12
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/core/reminder.py +342 -0
- bazaar_compute_node-0.1.9/src/bazaar_compute_node/core/reminder_schedule.py +330 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/storage.py +88 -0
- bazaar_compute_node-0.1.7/PKG-INFO +0 -184
- bazaar_compute_node-0.1.7/README.md +0 -171
- bazaar_compute_node-0.1.7/src/bazaar_compute_node/bcc.py +0 -529
- bazaar_compute_node-0.1.7/src/bazaar_compute_node/contrib/wecom/plugin.py +0 -29
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/LICENSE +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/__init__.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/__init__.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/attachments.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/transport.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/windows_pipe.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/wrapper.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/__init__.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/codex/__init__.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/codex/client.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/codex/events.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/codex/plugin.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/codex/process.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/codex/protocol.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/codex/runtime.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/logging/__init__.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/logging/audit.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/logging/plugin.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/sqlite/codec.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/sqlite/database.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/sqlite/migrations.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/sqlite/repository.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/wecom/__init__.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/wecom/markdown.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/contrib/wecom/outbound.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/__init__.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/approval.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/audit.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/client.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/concurrency.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/correlation.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/lifecycle.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/observability.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/orchestration/command.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/orchestration/services.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/outcomes.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/paths.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/runtime.py +0 -0
- {bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/core/timerwheel.py +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bazaar-compute-node
|
|
3
|
+
Version: 0.1.9
|
|
4
|
+
Summary: Runtime-agnostic computer node daemon for agents and channels.
|
|
5
|
+
License-Expression: AGPL-3.0-only
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: aiohttp>=3.12.0
|
|
8
|
+
Requires-Dist: aiosqlite>=0.20.0
|
|
9
|
+
Requires-Dist: cryptography>=45.0.0
|
|
10
|
+
Requires-Python: >=3.14
|
|
11
|
+
Project-URL: Repository, https://github.com/yuchanns/bazaar-compute-node
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# Bazaar Compute Node
|
|
15
|
+
|
|
16
|
+
Collaborate with your Agents in the bazaar across compute nodes, through any interface, with any harness runtime.
|
|
17
|
+
在集市里与你的 Agent 们合作,透过任意界面与任意 Harness。
|
|
18
|
+
|
|
19
|
+
<p align="left">
|
|
20
|
+
<a href="https://github.com/yuchanns/bazaar-compute-node/actions"><img
|
|
21
|
+
src="https://github.com/yuchanns/bazaar-compute-node/actions/workflows/release.yml/badge.svg"
|
|
22
|
+
alt="Release"
|
|
23
|
+
/></a>
|
|
24
|
+
<a href="https://pypi.org/project/bazaar-compute-node"><img
|
|
25
|
+
src="https://img.shields.io/pypi/v/bazaar-compute-node.svg"
|
|
26
|
+
alt="Python Package Index"
|
|
27
|
+
/></a>
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
**Documentation is coming soon...**
|
|
31
|
+
|
|
32
|
+
## Quick Start / 快速开始
|
|
33
|
+
|
|
34
|
+
Python 3.14+ is required:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
# Install
|
|
38
|
+
uv tool install bazaar-compute-node
|
|
39
|
+
bcn --version
|
|
40
|
+
|
|
41
|
+
# Upgrade
|
|
42
|
+
uv tool upgrade bazaar-compute-node
|
|
43
|
+
|
|
44
|
+
# Start daemon
|
|
45
|
+
export BCN_WECOM_BOT_SECRET='your-bot-secret'
|
|
46
|
+
|
|
47
|
+
bcn start --channel wecom --runtime codex \
|
|
48
|
+
--model gpt-5.6-luna --effort max \
|
|
49
|
+
--sandbox-mode workspace-write \
|
|
50
|
+
--network-access true \
|
|
51
|
+
--idle-timeout 600
|
|
52
|
+
|
|
53
|
+
# Stop daemon
|
|
54
|
+
bcn stop
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Features / 功能
|
|
58
|
+
|
|
59
|
+
- ✅ Done / 已完成
|
|
60
|
+
- 🚧 Working in progress / 开发中
|
|
61
|
+
|
|
62
|
+
### Facilities / 通用能力
|
|
63
|
+
|
|
64
|
+
| Status / 状态 | Ability / 能力 |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| ✅ | Reminders / 定时器 |
|
|
67
|
+
| ✅ | Attachments / 附件 |
|
|
68
|
+
| 🚧 | Multi-Agents / 多 Agent |
|
|
69
|
+
| 🚧 | Teams / 团队协作 |
|
|
70
|
+
|
|
71
|
+
### Channels / 渠道
|
|
72
|
+
|
|
73
|
+
| Status / 状态 | Channel / 渠道 |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| ✅ | WeCom / 企业微信 |
|
|
76
|
+
| ✅ | Telegram |
|
|
77
|
+
| 🚧 | GitHub |
|
|
78
|
+
| 🚧 | GitLab |
|
|
79
|
+
|
|
80
|
+
### Harnesses
|
|
81
|
+
|
|
82
|
+
| Status / 状态 | Runtime / 运行时 |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| ✅ | Codex |
|
|
85
|
+
| 🚧 | Claude Code |
|
|
86
|
+
| 🚧 | Pi |
|
|
87
|
+
| 🚧 | Hermes Agent |
|
|
88
|
+
| 🚧 | DeepSeek Harness |
|
|
89
|
+
|
|
90
|
+
### Platforms / 平台
|
|
91
|
+
|
|
92
|
+
| Status / 状态 | Platform / 平台 |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| ✅ | Windows |
|
|
95
|
+
| ✅ | macOS |
|
|
96
|
+
| ✅ | Linux |
|
|
97
|
+
|
|
98
|
+
## License / 许可证
|
|
99
|
+
|
|
100
|
+
This project is licensed under the [AGPLv3](./LICENSE).
|
|
101
|
+
本项目采用 [AGPLv3](./LICENSE) 许可证。
|
|
102
|
+
|
|
103
|
+
## Credits / 致谢
|
|
104
|
+
|
|
105
|
+
This project is inspired by [raft.build](https://raft.build).
|
|
106
|
+
本项目的灵感来自 [raft.build](https://raft.build)。
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Bazaar Compute Node
|
|
2
|
+
|
|
3
|
+
Collaborate with your Agents in the bazaar across compute nodes, through any interface, with any harness runtime.
|
|
4
|
+
在集市里与你的 Agent 们合作,透过任意界面与任意 Harness。
|
|
5
|
+
|
|
6
|
+
<p align="left">
|
|
7
|
+
<a href="https://github.com/yuchanns/bazaar-compute-node/actions"><img
|
|
8
|
+
src="https://github.com/yuchanns/bazaar-compute-node/actions/workflows/release.yml/badge.svg"
|
|
9
|
+
alt="Release"
|
|
10
|
+
/></a>
|
|
11
|
+
<a href="https://pypi.org/project/bazaar-compute-node"><img
|
|
12
|
+
src="https://img.shields.io/pypi/v/bazaar-compute-node.svg"
|
|
13
|
+
alt="Python Package Index"
|
|
14
|
+
/></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
**Documentation is coming soon...**
|
|
18
|
+
|
|
19
|
+
## Quick Start / 快速开始
|
|
20
|
+
|
|
21
|
+
Python 3.14+ is required:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
# Install
|
|
25
|
+
uv tool install bazaar-compute-node
|
|
26
|
+
bcn --version
|
|
27
|
+
|
|
28
|
+
# Upgrade
|
|
29
|
+
uv tool upgrade bazaar-compute-node
|
|
30
|
+
|
|
31
|
+
# Start daemon
|
|
32
|
+
export BCN_WECOM_BOT_SECRET='your-bot-secret'
|
|
33
|
+
|
|
34
|
+
bcn start --channel wecom --runtime codex \
|
|
35
|
+
--model gpt-5.6-luna --effort max \
|
|
36
|
+
--sandbox-mode workspace-write \
|
|
37
|
+
--network-access true \
|
|
38
|
+
--idle-timeout 600
|
|
39
|
+
|
|
40
|
+
# Stop daemon
|
|
41
|
+
bcn stop
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Features / 功能
|
|
45
|
+
|
|
46
|
+
- ✅ Done / 已完成
|
|
47
|
+
- 🚧 Working in progress / 开发中
|
|
48
|
+
|
|
49
|
+
### Facilities / 通用能力
|
|
50
|
+
|
|
51
|
+
| Status / 状态 | Ability / 能力 |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| ✅ | Reminders / 定时器 |
|
|
54
|
+
| ✅ | Attachments / 附件 |
|
|
55
|
+
| 🚧 | Multi-Agents / 多 Agent |
|
|
56
|
+
| 🚧 | Teams / 团队协作 |
|
|
57
|
+
|
|
58
|
+
### Channels / 渠道
|
|
59
|
+
|
|
60
|
+
| Status / 状态 | Channel / 渠道 |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| ✅ | WeCom / 企业微信 |
|
|
63
|
+
| ✅ | Telegram |
|
|
64
|
+
| 🚧 | GitHub |
|
|
65
|
+
| 🚧 | GitLab |
|
|
66
|
+
|
|
67
|
+
### Harnesses
|
|
68
|
+
|
|
69
|
+
| Status / 状态 | Runtime / 运行时 |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| ✅ | Codex |
|
|
72
|
+
| 🚧 | Claude Code |
|
|
73
|
+
| 🚧 | Pi |
|
|
74
|
+
| 🚧 | Hermes Agent |
|
|
75
|
+
| 🚧 | DeepSeek Harness |
|
|
76
|
+
|
|
77
|
+
### Platforms / 平台
|
|
78
|
+
|
|
79
|
+
| Status / 状态 | Platform / 平台 |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| ✅ | Windows |
|
|
82
|
+
| ✅ | macOS |
|
|
83
|
+
| ✅ | Linux |
|
|
84
|
+
|
|
85
|
+
## License / 许可证
|
|
86
|
+
|
|
87
|
+
This project is licensed under the [AGPLv3](./LICENSE).
|
|
88
|
+
本项目采用 [AGPLv3](./LICENSE) 许可证。
|
|
89
|
+
|
|
90
|
+
## Credits / 致谢
|
|
91
|
+
|
|
92
|
+
This project is inspired by [raft.build](https://raft.build).
|
|
93
|
+
本项目的灵感来自 [raft.build](https://raft.build)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "bazaar-compute-node"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.9"
|
|
4
4
|
description = "Runtime-agnostic computer node daemon for agents and channels."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "AGPL-3.0-only"
|
|
@@ -22,7 +22,8 @@ bcn = "bazaar_compute_node.cli:main"
|
|
|
22
22
|
codex = "bazaar_compute_node.contrib.codex.plugin:create_runtime"
|
|
23
23
|
|
|
24
24
|
[project.entry-points."bazaar_compute_node.channels"]
|
|
25
|
-
wecom = "bazaar_compute_node.contrib.wecom.plugin:
|
|
25
|
+
wecom = "bazaar_compute_node.contrib.wecom.plugin:builder"
|
|
26
|
+
telegram = "bazaar_compute_node.contrib.telegram.plugin:builder"
|
|
26
27
|
|
|
27
28
|
[project.entry-points."bazaar_compute_node.storages"]
|
|
28
29
|
sqlite = "bazaar_compute_node.contrib.sqlite.plugin:create_storage"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "bazaar-compute-node"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.9"
|
|
4
4
|
description = "Runtime-agnostic computer node daemon for agents and channels."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "AGPL-3.0-only"
|
|
@@ -22,7 +22,8 @@ bcn = "bazaar_compute_node.cli:main"
|
|
|
22
22
|
codex = "bazaar_compute_node.contrib.codex.plugin:create_runtime"
|
|
23
23
|
|
|
24
24
|
[project.entry-points."bazaar_compute_node.channels"]
|
|
25
|
-
wecom = "bazaar_compute_node.contrib.wecom.plugin:
|
|
25
|
+
wecom = "bazaar_compute_node.contrib.wecom.plugin:builder"
|
|
26
|
+
telegram = "bazaar_compute_node.contrib.telegram.plugin:builder"
|
|
26
27
|
|
|
27
28
|
[project.entry-points."bazaar_compute_node.storages"]
|
|
28
29
|
sqlite = "bazaar_compute_node.contrib.sqlite.plugin:create_storage"
|
{bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/application.py
RENAMED
|
@@ -11,20 +11,20 @@ from collections.abc import Mapping, Sequence
|
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
13
|
from ..core.channel import ChannelContext, IChannel
|
|
14
|
+
from ..core.concurrency import SessionLockRegistry
|
|
14
15
|
from ..core.lifecycle import TimeoutBudget
|
|
15
16
|
from ..core.models import RuntimeSession
|
|
16
17
|
from ..core.observability import IAudit
|
|
17
|
-
from ..core.orchestration import SessionOrchestrator
|
|
18
|
+
from ..core.orchestration import ReminderScheduler, SessionOrchestrator
|
|
19
|
+
from ..core.orchestration.reminder_command import ReminderCommandService
|
|
18
20
|
from ..core.paths import resolve_data_dir, resolve_workspace_dir
|
|
19
21
|
from ..core.runtime import IRuntime, RuntimeCommandContext, RuntimeSandboxMode
|
|
20
22
|
from ..core.storage import IStorage, NodeIdentity
|
|
21
23
|
from ..core.timerwheel import TimerWheel
|
|
22
24
|
from .attachments import AttachmentMaterializer
|
|
23
|
-
from .command import
|
|
24
|
-
CommandDispatcher,
|
|
25
|
-
CommandDispatchError,
|
|
26
|
-
)
|
|
25
|
+
from .command import CommandDispatchError
|
|
27
26
|
from .registry import AdapterFactories
|
|
27
|
+
from .reminder_dispatch import CommandDispatcher
|
|
28
28
|
from .transport import LocalCommandServer
|
|
29
29
|
from .wrapper import install_bcc_wrapper, remove_bcc_wrapper
|
|
30
30
|
|
|
@@ -85,13 +85,14 @@ class NodeApplication:
|
|
|
85
85
|
self._wrapper_path: Path | None = None
|
|
86
86
|
self._identity: NodeIdentity | None = None
|
|
87
87
|
self._session_capabilities: dict[str, tuple[str, str]] = {}
|
|
88
|
+
self._concurrency = SessionLockRegistry()
|
|
88
89
|
self._started = False
|
|
89
90
|
self._stopped = asyncio.Event()
|
|
90
91
|
self._runtime_environment_include = tuple(runtime_environment_include)
|
|
91
92
|
self._attachment_materializer = AttachmentMaterializer(
|
|
92
93
|
self._workspace_path, self._referenced_attachment_paths
|
|
93
94
|
)
|
|
94
|
-
self.channel: IChannel = factories.channel(
|
|
95
|
+
self.channel: IChannel = factories.channel.build(
|
|
95
96
|
ChannelContext(
|
|
96
97
|
attachments=self._attachment_materializer,
|
|
97
98
|
options=dict(channel_options or {}),
|
|
@@ -136,14 +137,27 @@ class NodeApplication:
|
|
|
136
137
|
timer_wheel=self.timer_wheel,
|
|
137
138
|
runtime_idle_timeout_ms=runtime_idle_timeout_ms,
|
|
138
139
|
workspace=self._workspace_path,
|
|
140
|
+
concurrency=self._concurrency,
|
|
139
141
|
on_node_initialized=self._ensure_workspace,
|
|
140
142
|
)
|
|
143
|
+
self.reminder_scheduler = ReminderScheduler(
|
|
144
|
+
storage=self.storage,
|
|
145
|
+
timer_wheel=self.timer_wheel,
|
|
146
|
+
concurrency=self._concurrency,
|
|
147
|
+
publish_wake=self.orchestrator.publish_reminder_wake,
|
|
148
|
+
)
|
|
149
|
+
self.reminder_service = ReminderCommandService(
|
|
150
|
+
storage=self.storage,
|
|
151
|
+
concurrency=self._concurrency,
|
|
152
|
+
poke=self.reminder_scheduler.poke,
|
|
153
|
+
)
|
|
141
154
|
self.command_service = self.orchestrator.command_service
|
|
142
155
|
control_handler = None
|
|
143
156
|
if factories.control is not None:
|
|
144
157
|
control_handler = factories.control(self._adapter_context())
|
|
145
158
|
self.command_dispatcher = CommandDispatcher(
|
|
146
159
|
self.command_service,
|
|
160
|
+
reminder_service=self.reminder_service,
|
|
147
161
|
timeout_budget=self.timeout_budget,
|
|
148
162
|
control_handler=self._handle_control,
|
|
149
163
|
session_binding_validator=self._validate_session_binding,
|
|
@@ -173,30 +187,38 @@ class NodeApplication:
|
|
|
173
187
|
await self.orchestrator.start(
|
|
174
188
|
timeout=self.timeout_budget.startup_seconds,
|
|
175
189
|
)
|
|
190
|
+
self._started = True
|
|
191
|
+
await self.reminder_scheduler.start(
|
|
192
|
+
timeout=self.timeout_budget.startup_seconds,
|
|
193
|
+
)
|
|
176
194
|
except BaseException:
|
|
177
195
|
try:
|
|
178
196
|
await self.stop()
|
|
179
197
|
finally:
|
|
180
198
|
await self.timer_wheel.close()
|
|
181
199
|
raise
|
|
182
|
-
self._started = True
|
|
183
200
|
self._stopped.clear()
|
|
184
201
|
self.command_dispatcher.start_accepting()
|
|
185
202
|
|
|
186
203
|
async def stop(self) -> None:
|
|
187
204
|
if not self._started:
|
|
188
205
|
try:
|
|
189
|
-
await self.
|
|
206
|
+
await self.reminder_scheduler.stop(
|
|
190
207
|
timeout=self.timeout_budget.shutdown_seconds,
|
|
191
208
|
)
|
|
192
209
|
finally:
|
|
193
210
|
try:
|
|
194
|
-
await self.
|
|
211
|
+
await self.command_dispatcher.drain(
|
|
212
|
+
timeout=self.timeout_budget.shutdown_seconds,
|
|
213
|
+
)
|
|
195
214
|
finally:
|
|
196
215
|
try:
|
|
197
|
-
await self.
|
|
216
|
+
await self.command_server.stop()
|
|
198
217
|
finally:
|
|
199
|
-
|
|
218
|
+
try:
|
|
219
|
+
await self._cleanup_bcc_wrapper()
|
|
220
|
+
finally:
|
|
221
|
+
await self.timer_wheel.close()
|
|
200
222
|
return
|
|
201
223
|
self._started = False
|
|
202
224
|
self.command_dispatcher.stop_accepting()
|
|
@@ -206,20 +228,25 @@ class NodeApplication:
|
|
|
206
228
|
)
|
|
207
229
|
finally:
|
|
208
230
|
try:
|
|
209
|
-
await self.
|
|
231
|
+
await self.reminder_scheduler.stop(
|
|
210
232
|
timeout=self.timeout_budget.shutdown_seconds,
|
|
211
233
|
)
|
|
212
234
|
finally:
|
|
213
235
|
try:
|
|
214
|
-
await self.
|
|
236
|
+
await self.orchestrator.stop(
|
|
237
|
+
timeout=self.timeout_budget.shutdown_seconds,
|
|
238
|
+
)
|
|
215
239
|
finally:
|
|
216
240
|
try:
|
|
217
|
-
await self.
|
|
241
|
+
await self.command_server.stop()
|
|
218
242
|
finally:
|
|
219
243
|
try:
|
|
220
|
-
await self.
|
|
244
|
+
await self._cleanup_bcc_wrapper()
|
|
221
245
|
finally:
|
|
222
|
-
|
|
246
|
+
try:
|
|
247
|
+
await self.timer_wheel.close()
|
|
248
|
+
finally:
|
|
249
|
+
self._stopped.set()
|
|
223
250
|
|
|
224
251
|
async def _cleanup_bcc_wrapper(self) -> None:
|
|
225
252
|
wrapper_path = self._wrapper_path
|
{bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/command.py
RENAMED
|
@@ -100,7 +100,7 @@ SessionBindingValidator = Callable[[str, Mapping[str, object]], Awaitable[None]]
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
class CommandDispatcher:
|
|
103
|
-
"""Translate local JSON requests into core command results."""
|
|
103
|
+
"""Translate resource-scoped local JSON requests into core command results."""
|
|
104
104
|
|
|
105
105
|
def __init__(
|
|
106
106
|
self,
|
|
@@ -222,20 +222,40 @@ class CommandDispatcher:
|
|
|
222
222
|
async def _dispatch_command(
|
|
223
223
|
self, request: Mapping[str, object]
|
|
224
224
|
) -> Mapping[str, object]:
|
|
225
|
-
|
|
226
|
-
if not isinstance(
|
|
225
|
+
resource = request.get("resource")
|
|
226
|
+
if not isinstance(resource, str) or not resource:
|
|
227
227
|
raise CommandDispatchError(
|
|
228
|
-
"
|
|
228
|
+
"RESOURCE_REQUIRED", "resource must be a non-empty string"
|
|
229
229
|
)
|
|
230
230
|
command = request.get("command")
|
|
231
231
|
if not isinstance(command, str) or not command:
|
|
232
232
|
raise CommandDispatchError(
|
|
233
233
|
"COMMAND_REQUIRED", "command must be a non-empty string"
|
|
234
234
|
)
|
|
235
|
+
if resource == "message":
|
|
236
|
+
if command not in {"check", "read", "send"}:
|
|
237
|
+
raise CommandDispatchError(
|
|
238
|
+
"UNKNOWN_COMMAND", f"unsupported message command: {command}"
|
|
239
|
+
)
|
|
240
|
+
elif resource == "thread":
|
|
241
|
+
if command != "unfollow":
|
|
242
|
+
raise CommandDispatchError(
|
|
243
|
+
"UNKNOWN_COMMAND", f"unsupported thread command: {command}"
|
|
244
|
+
)
|
|
245
|
+
else:
|
|
246
|
+
raise CommandDispatchError(
|
|
247
|
+
"UNKNOWN_RESOURCE", f"unsupported command resource: {resource}"
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
session_id = request.get("session_id")
|
|
251
|
+
if not isinstance(session_id, str) or not session_id:
|
|
252
|
+
raise CommandDispatchError(
|
|
253
|
+
"SESSION_REQUIRED", "session_id must be a non-empty string"
|
|
254
|
+
)
|
|
235
255
|
if self._session_binding_validator is not None:
|
|
236
256
|
await self._session_binding_validator(session_id, request)
|
|
237
257
|
|
|
238
|
-
if command == "check":
|
|
258
|
+
if resource == "message" and command == "check":
|
|
239
259
|
result = await self._service.check(session_id)
|
|
240
260
|
return {
|
|
241
261
|
"ok": True,
|
|
@@ -252,7 +272,7 @@ class CommandDispatcher:
|
|
|
252
272
|
},
|
|
253
273
|
}
|
|
254
274
|
|
|
255
|
-
if command == "read":
|
|
275
|
+
if resource == "message" and command == "read":
|
|
256
276
|
target = request.get("target")
|
|
257
277
|
if not isinstance(target, str) or not target:
|
|
258
278
|
raise CommandDispatchError(
|
|
@@ -290,7 +310,7 @@ class CommandDispatcher:
|
|
|
290
310
|
},
|
|
291
311
|
}
|
|
292
312
|
|
|
293
|
-
if command == "send":
|
|
313
|
+
if resource == "message" and command == "send":
|
|
294
314
|
target = request.get("target")
|
|
295
315
|
body = request.get("body")
|
|
296
316
|
command_id = request.get("command_id")
|
|
@@ -343,7 +363,7 @@ class CommandDispatcher:
|
|
|
343
363
|
"result": {"outbound": serialize_outbound(result)},
|
|
344
364
|
}
|
|
345
365
|
|
|
346
|
-
if command == "unfollow":
|
|
366
|
+
if resource == "thread" and command == "unfollow":
|
|
347
367
|
target = request.get("target")
|
|
348
368
|
if not isinstance(target, str) or not target:
|
|
349
369
|
raise CommandDispatchError(
|
|
@@ -352,10 +372,12 @@ class CommandDispatcher:
|
|
|
352
372
|
changed = await self._service.unfollow(session_id, target=target)
|
|
353
373
|
return {"ok": True, "result": {"changed": changed}}
|
|
354
374
|
|
|
355
|
-
raise
|
|
375
|
+
raise AssertionError("validated command route has no handler")
|
|
356
376
|
|
|
357
377
|
|
|
358
378
|
def format_message_time(timestamp_ms: int) -> str:
|
|
359
|
-
return
|
|
360
|
-
|
|
379
|
+
return (
|
|
380
|
+
datetime.fromtimestamp(timestamp_ms / 1000, tz=UTC)
|
|
381
|
+
.astimezone()
|
|
382
|
+
.strftime("%Y-%m-%d %H:%M:%S")
|
|
361
383
|
)
|
{bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/config.py
RENAMED
|
@@ -3,8 +3,10 @@ from __future__ import annotations
|
|
|
3
3
|
import math
|
|
4
4
|
import os
|
|
5
5
|
import tomllib
|
|
6
|
-
from
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from dataclasses import dataclass, field
|
|
7
8
|
from pathlib import Path
|
|
9
|
+
from types import MappingProxyType
|
|
8
10
|
|
|
9
11
|
from ..core.paths import resolve_data_dir
|
|
10
12
|
from ..core.runtime import RuntimeSandboxMode
|
|
@@ -28,8 +30,9 @@ class NodeConfiguration:
|
|
|
28
30
|
network_access: bool = True
|
|
29
31
|
runtime_idle_timeout_seconds: float = 0
|
|
30
32
|
runtime_env_include: tuple[str, ...] = ()
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
channel_options: Mapping[str, Mapping[str, object]] = field(
|
|
34
|
+
default_factory=lambda: MappingProxyType({})
|
|
35
|
+
)
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
class ConfigurationError(ValueError):
|
|
@@ -67,9 +70,13 @@ def load_node_configuration(path: Path | None = None) -> NodeConfiguration:
|
|
|
67
70
|
channel = payload.get("channel", {})
|
|
68
71
|
if not isinstance(channel, dict):
|
|
69
72
|
raise ConfigurationError("[channel] must be a TOML table")
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
channel_options: dict[str, Mapping[str, object]] = {}
|
|
74
|
+
for channel_name, options in channel.items():
|
|
75
|
+
if not channel_name:
|
|
76
|
+
raise ConfigurationError("channel name must be non-empty text")
|
|
77
|
+
if not isinstance(options, dict):
|
|
78
|
+
raise ConfigurationError(f"[channel.{channel_name}] must be a TOML table")
|
|
79
|
+
channel_options[channel_name] = MappingProxyType(dict(options))
|
|
73
80
|
sandbox_mode = runtime.get("sandbox_mode", RuntimeSandboxMode.WORKSPACE_WRITE.value)
|
|
74
81
|
if not isinstance(sandbox_mode, str):
|
|
75
82
|
raise ConfigurationError("runtime.sandbox_mode must be text")
|
|
@@ -105,10 +112,7 @@ def load_node_configuration(path: Path | None = None) -> NodeConfiguration:
|
|
|
105
112
|
runtime_env_include=_text_list(
|
|
106
113
|
runtime_env.get("include", []), "runtime.env.include"
|
|
107
114
|
),
|
|
108
|
-
|
|
109
|
-
wecom_websocket_url=_optional_text(
|
|
110
|
-
wecom.get("websocket_url"), "channel.wecom.websocket_url"
|
|
111
|
-
),
|
|
115
|
+
channel_options=MappingProxyType(channel_options),
|
|
112
116
|
)
|
|
113
117
|
|
|
114
118
|
|
{bazaar_compute_node-0.1.7 → bazaar_compute_node-0.1.9}/src/bazaar_compute_node/app/registry.py
RENAMED
|
@@ -6,7 +6,7 @@ from functools import partial
|
|
|
6
6
|
from importlib.metadata import EntryPoint, entry_points
|
|
7
7
|
from typing import Any, cast
|
|
8
8
|
|
|
9
|
-
from ..core.channel import
|
|
9
|
+
from ..core.channel import IChannelBuilder
|
|
10
10
|
from ..core.observability import IAudit
|
|
11
11
|
from ..core.runtime import IRuntime, RuntimeCommandContext
|
|
12
12
|
from ..core.storage import IStorage
|
|
@@ -18,7 +18,6 @@ STORAGE_ENTRY_POINT_GROUP = "bazaar_compute_node.storages"
|
|
|
18
18
|
AUDIT_ENTRY_POINT_GROUP = "bazaar_compute_node.audits"
|
|
19
19
|
CONTROL_ENTRY_POINT_GROUP = "bazaar_compute_node.controls"
|
|
20
20
|
|
|
21
|
-
ChannelFactory = Callable[[ChannelContext], IChannel]
|
|
22
21
|
RuntimeFactory = Callable[[RuntimeCommandContext], IRuntime]
|
|
23
22
|
StorageFactory = Callable[[], IStorage]
|
|
24
23
|
AuditFactory = Callable[[], IAudit]
|
|
@@ -26,7 +25,7 @@ AuditFactory = Callable[[], IAudit]
|
|
|
26
25
|
|
|
27
26
|
@dataclass(frozen=True, slots=True)
|
|
28
27
|
class AdapterFactories:
|
|
29
|
-
channel:
|
|
28
|
+
channel: IChannelBuilder
|
|
30
29
|
runtime: RuntimeFactory
|
|
31
30
|
storage: StorageFactory
|
|
32
31
|
audit: AuditFactory
|
|
@@ -60,10 +59,7 @@ class AdapterRegistry:
|
|
|
60
59
|
if storage_options:
|
|
61
60
|
storage_factory = partial(storage_factory, dict(storage_options))
|
|
62
61
|
return AdapterFactories(
|
|
63
|
-
channel=
|
|
64
|
-
ChannelFactory,
|
|
65
|
-
self._load(CHANNEL_ENTRY_POINT_GROUP, channel),
|
|
66
|
-
),
|
|
62
|
+
channel=self._load_channel_builder(channel),
|
|
67
63
|
runtime=cast(
|
|
68
64
|
RuntimeFactory,
|
|
69
65
|
self._load(RUNTIME_ENTRY_POINT_GROUP, runtime),
|
|
@@ -79,6 +75,27 @@ class AdapterRegistry:
|
|
|
79
75
|
),
|
|
80
76
|
)
|
|
81
77
|
|
|
78
|
+
def _load_channel_builder(self, name: str) -> IChannelBuilder:
|
|
79
|
+
entry_point = self._find(CHANNEL_ENTRY_POINT_GROUP, name)
|
|
80
|
+
if entry_point is None:
|
|
81
|
+
raise ProviderLoadError(
|
|
82
|
+
f"provider '{name}' is not installed for entry point group "
|
|
83
|
+
f"'{CHANNEL_ENTRY_POINT_GROUP}'"
|
|
84
|
+
)
|
|
85
|
+
try:
|
|
86
|
+
builder = entry_point.load()
|
|
87
|
+
except Exception as error:
|
|
88
|
+
raise ProviderLoadError(
|
|
89
|
+
f"failed to load provider '{name}' from "
|
|
90
|
+
f"'{CHANNEL_ENTRY_POINT_GROUP}': {error}"
|
|
91
|
+
) from error
|
|
92
|
+
if not callable(getattr(builder, "build", None)):
|
|
93
|
+
raise ProviderLoadError(
|
|
94
|
+
f"provider '{name}' from '{CHANNEL_ENTRY_POINT_GROUP}' "
|
|
95
|
+
"does not provide a callable build method"
|
|
96
|
+
)
|
|
97
|
+
return cast(IChannelBuilder, builder)
|
|
98
|
+
|
|
82
99
|
def _load(self, group: str, name: str) -> Any:
|
|
83
100
|
entry_point = self._find(group, name)
|
|
84
101
|
if entry_point is None:
|