aaas-service 0.1.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 (40) hide show
  1. aaas_service-0.1.0/.env.example +24 -0
  2. aaas_service-0.1.0/LICENSE +201 -0
  3. aaas_service-0.1.0/MANIFEST.in +22 -0
  4. aaas_service-0.1.0/PKG-INFO +309 -0
  5. aaas_service-0.1.0/PROPOSAL-aaas-agentscope.md +386 -0
  6. aaas_service-0.1.0/README-IMPLEMENTATION.md +251 -0
  7. aaas_service-0.1.0/README.md +281 -0
  8. aaas_service-0.1.0/REVIEW-jev.md +111 -0
  9. aaas_service-0.1.0/aaas_service/__init__.py +117 -0
  10. aaas_service-0.1.0/aaas_service/__main__.py +34 -0
  11. aaas_service-0.1.0/aaas_service/app.py +250 -0
  12. aaas_service-0.1.0/aaas_service/decode.py +156 -0
  13. aaas_service-0.1.0/aaas_service/events.py +229 -0
  14. aaas_service-0.1.0/aaas_service/handler.py +206 -0
  15. aaas_service-0.1.0/aaas_service/history.py +173 -0
  16. aaas_service-0.1.0/aaas_service/providers.py +397 -0
  17. aaas_service-0.1.0/aaas_service/py.typed +0 -0
  18. aaas_service-0.1.0/aaas_service/tools.py +200 -0
  19. aaas_service-0.1.0/aaas_service/usage.py +106 -0
  20. aaas_service-0.1.0/aaas_service/validate.py +273 -0
  21. aaas_service-0.1.0/aaas_service.egg-info/PKG-INFO +309 -0
  22. aaas_service-0.1.0/aaas_service.egg-info/SOURCES.txt +38 -0
  23. aaas_service-0.1.0/aaas_service.egg-info/dependency_links.txt +1 -0
  24. aaas_service-0.1.0/aaas_service.egg-info/entry_points.txt +2 -0
  25. aaas_service-0.1.0/aaas_service.egg-info/requires.txt +7 -0
  26. aaas_service-0.1.0/aaas_service.egg-info/top_level.txt +1 -0
  27. aaas_service-0.1.0/conftest.py +29 -0
  28. aaas_service-0.1.0/pyproject.toml +71 -0
  29. aaas_service-0.1.0/pytest.ini +9 -0
  30. aaas_service-0.1.0/requirements-dev.txt +5 -0
  31. aaas_service-0.1.0/requirements.txt +7 -0
  32. aaas_service-0.1.0/setup.cfg +4 -0
  33. aaas_service-0.1.0/srcpath.py +193 -0
  34. aaas_service-0.1.0/tests/scripted.py +160 -0
  35. aaas_service-0.1.0/tests/test_bridge.py +438 -0
  36. aaas_service-0.1.0/tests/test_config.py +129 -0
  37. aaas_service-0.1.0/tests/test_env.py +344 -0
  38. aaas_service-0.1.0/tests/test_live.py +181 -0
  39. aaas_service-0.1.0/tests/test_packaging.py +154 -0
  40. aaas_service-0.1.0/tests/test_review_fixes.py +166 -0
@@ -0,0 +1,24 @@
1
+ # 本文件只是变量清单,不含任何真实值;拷成 .env 后填自己的(.env 已被 gitignore)。
2
+ # 优先级:命令行参数 > AAAS_* > 提供方约定变量 > 内置默认(见 aaas_service/providers.py)。
3
+
4
+ # 提供方:openai | deepseek | dashscope | anthropic
5
+ AAAS_PROVIDER=deepseek
6
+ # 模型名。注意它是**进程级**的、不区分提供方:换 provider 前先清掉,否则会跨过去。
7
+ AAAS_MODEL=
8
+ # 自建网关 / 代理地址(需带 scheme)
9
+ AAAS_BASE_URL=
10
+ # 通用凭据兜底;也可以改用各提供方的约定变量
11
+ AAAS_API_KEY=
12
+
13
+ # 提供方约定变量(选一个填即可)
14
+ DEEPSEEK_API_KEY=
15
+ OPENAI_API_KEY=
16
+ OPENAI_BASE_URL=
17
+ DASHSCOPE_API_KEY=
18
+ ANTHROPIC_API_KEY=
19
+
20
+ # aaas SDK 源码目录(未 pip install 时必需;也可以写进 .aaas-src)
21
+ AAAS_SRC=
22
+
23
+ # 置 1 才跑会真花钱的 live 用例
24
+ AAAS_LIVE=
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2026 the aaas-service authors
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,22 @@
1
+ # sdist 里要有「跑得起来看」的东西;wheel 里只放包(见 pyproject 的 packages)。
2
+ #
3
+ # 为什么 tests 进 sdist:下游打包者(发行版、公司内镜像)跑测试是标准动作,而一份
4
+ # 没有测试的源码包等于让他们只能靠读代码判断真伪。tests 依赖 conftest.py 与
5
+ # srcpath.py,所以三者必须一起进 —— 只放 tests 会得到一个 import 就崩的测试目录。
6
+ include LICENSE
7
+ include README.md
8
+ include README-IMPLEMENTATION.md
9
+ include PROPOSAL-aaas-agentscope.md
10
+ include REVIEW-jev.md
11
+ include requirements.txt
12
+ include requirements-dev.txt
13
+ include pytest.ini
14
+ include conftest.py
15
+ include srcpath.py
16
+ recursive-include tests *.py
17
+
18
+ # 模板要进:它是唯一一处集中记录 AAAS_* 变量名的地方(里面没有任何真实值)。
19
+ include .env.example
20
+
21
+ # 反过来:运行期产物与本地配置永远不进包。
22
+ global-exclude __pycache__ *.py[cod] .aaas-src .env
@@ -0,0 +1,309 @@
1
+ Metadata-Version: 2.4
2
+ Name: aaas-service
3
+ Version: 0.1.0
4
+ Summary: 用 AgentScope 驱动的 AaaS(Agent as a Service)协议服务端:模型在服务端,能力与副作用全部回到调用方进程
5
+ License-Expression: Apache-2.0
6
+ Project-URL: Homepage, https://github.com/YY-Yifei/openagent-aaas
7
+ Project-URL: Repository, https://github.com/YY-Yifei/openagent-aaas
8
+ Project-URL: Issues, https://github.com/YY-Yifei/openagent-aaas/issues
9
+ Project-URL: Specification, https://github.com/YY-Yifei/aaas/blob/main/PROTOCOL.md
10
+ Keywords: aaas,agent-as-a-service,agentscope,llm,mcp,function-calling,websocket
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Framework :: AsyncIO
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: agentscope<2.1,>=2.0.5
22
+ Requires-Dist: aaas<0.3,>=0.2.1
23
+ Provides-Extra: test
24
+ Requires-Dist: pytest>=8; extra == "test"
25
+ Requires-Dist: pytest-asyncio>=0.24; extra == "test"
26
+ Requires-Dist: pydantic>=2; extra == "test"
27
+ Dynamic: license-file
28
+
29
+ # aaas-service
30
+
31
+ 用 [AgentScope](https://github.com/agentscope-ai/agentscope) 驱动的 **AaaS(Agent as a Service)协议**
32
+ 服务端参考实现。
33
+
34
+ 一句话概括它和其它 Agent 服务的区别:
35
+
36
+ > **服务端没有内置能力。** 调用方声明什么函数,模型就只能伸到什么能力;
37
+ > 而每一次伸手,都伸回**调用方自己的进程**去执行。
38
+
39
+ 所以模型、凭据、业务数据全在你的进程里,服务端只是一个「会思考但手无寸铁」的壳。
40
+
41
+ ---
42
+
43
+ ## 安装
44
+
45
+ ```bash
46
+ pip install aaas-service
47
+ ```
48
+
49
+ ```bash
50
+ set "DEEPSEEK_API_KEY=sk-..." # bash: export DEEPSEEK_API_KEY=sk-...
51
+ aaas-service # 等价于 python -m aaas_service,默认监听 127.0.0.1:8888
52
+ aaas-service --print-config # 不起服务、不联网、不要 key,只告诉你每个配置值来自哪
53
+ ```
54
+
55
+ 只需要 Python ≥ 3.11(下限由 `agentscope` 决定)。仓库在
56
+ [github.com/YY-Yifei/openagent-aaas](https://github.com/YY-Yifei/openagent-aaas);
57
+ 想改代码、跑测试,看下面「依赖」与「跑测试」。
58
+
59
+ ## 它做了什么
60
+
61
+ | 能力 | 说明 |
62
+ |---|---|
63
+ | 单轮 ReAct 闭环 | `handler(ctx)` 一个函数里跑完「模型 → 工具 → 模型 → 收尾」 |
64
+ | 反向 function calling | 工具调用经协议回到调用方执行,服务端不持有任何实现与凭据 |
65
+ | 流式回复 | 文本 / 思考块 / 工具事件分段推送,`block_id` 直接映射 `message_id` |
66
+ | stateless 会话 | 每轮由调用方重放 history,服务端零记忆(可切 `session` 模式) |
67
+ | 用量上报 | token / 工具次数;**拿不到就不填,绝不写 0** |
68
+ | 模型配置 | 提供方 / 模型名 / 地址 / 凭据四件事,一律从命令行 + 环境变量来 |
69
+
70
+ ```
71
+ aaas_service/ 服务端实现(**只有这个包进 wheel**)
72
+ app.py 装配 + 命令行入口(--print-config / --host / --port …)
73
+ handler.py 唯一的接缝:async def handler(ctx)
74
+ providers.py 提供方表 + 四个旋钮的解析(命令行 > AAAS_* > 约定变量 > 默认)
75
+ events.py AgentScope 事件 → AaaS 协议的桥
76
+ tools.py 协议里的 JSON Schema → 可直接调用的工具
77
+ usage.py token / 调用计数(未知 ≠ 0)
78
+ history.py 历史重放与裁剪
79
+ validate.py 入参校验
80
+ pyproject.toml 打包元数据(PEP 621;版本真源 = aaas_service.__version__)
81
+ scripts/
82
+ chat.py 交互式调用方(工具在你自己进程里执行)
83
+ service_ctl.py 起停 / 状态(真握手探活,不是裸端口探测)
84
+ tests/ 单元 + 端到端(默认全离线,不联网不花钱)
85
+ srcpath.py 定位 aaas SDK 源码(AAAS_SRC / .aaas-src)—— **开发用,不打包**
86
+ README-IMPLEMENTATION.md 实施说明:每条设计决策背后的实测与坑
87
+ PROPOSAL-aaas-agentscope.md 方案与两侧事实核对
88
+ REVIEW-jev.md 关键判定的决策记录
89
+ ```
90
+
91
+ `scripts/`、`tests/`、`srcpath.py` 都依赖仓库布局,所以**不进 wheel**:
92
+ `pip install aaas-service` 只会装 `aaas_service` 一个包(`tests/test_packaging.py` 守着这条)。 app.py 装配 + 命令行入口(--print-config / --host / --port …)
93
+ handler.py 唯一的接缝:async def handler(ctx)
94
+ providers.py 提供方表 + 四个旋钮的解析(命令行 > AAAS_* > 约定变量 > 默认)
95
+ events.py AgentScope 事件 → AaaS 协议的桥
96
+ tools.py 协议里的 JSON Schema → 可直接调用的工具
97
+ usage.py token / 调用计数(未知 ≠ 0)
98
+ history.py 历史重放与裁剪
99
+ validate.py 入参校验
100
+ scripts/
101
+ chat.py 交互式调用方(工具在你自己进程里执行)
102
+ service_ctl.py 起停 / 状态(真握手探活,不是裸端口探测)
103
+ tests/ 单元 + 端到端(默认全离线,不联网不花钱)
104
+ srcpath.py 定位 aaas SDK 源码(AAAS_SRC / .aaas-src)
105
+ README-IMPLEMENTATION.md 实施说明:每条设计决策背后的实测与坑
106
+ PROPOSAL-aaas-agentscope.md 方案与两侧事实核对
107
+ REVIEW-jev.md 关键判定的决策记录
108
+ ```
109
+
110
+ ## 依赖
111
+
112
+ - Python ≥ 3.11 —— 这是 `agentscope` 的要求;本仓库在 3.12 上实测(语法用
113
+ `ast.parse(feature_version=…)` 一路验到 3.9 都能解析,但下限由依赖说了算)
114
+ - 一次装齐(`agentscope` + `aaas` + `pytest`):`pip install -e ".[test]"`
115
+
116
+ **aaas SDK 已发布到 PyPI**([`aaas`](https://pypi.org/project/aaas/) 0.2.1),
117
+ `pip install` 会一并装上,**不需要** `AAAS_SRC` 了。剩下的唯一用途是「我要改 aaas
118
+ 源码」——那时把它的 `src` 指过来,本项目的 `conftest.py` / `scripts` 会优先用它:
119
+
120
+ ```bash
121
+ # 方式一:环境变量
122
+ set "AAAS_SRC=D:\path\to\aaas\src" # bash: export AAAS_SRC=/path/to/aaas/src
123
+ # 方式二:仓库根写一行(已 gitignore,适合本地长期开发)
124
+ echo D:\path\to\aaas\src > .aaas-src
125
+ ```
126
+
127
+ 代码里**不写死任何路径**:两条路都没有时,`conftest.py` 会明确告诉你缺什么,
128
+ 而不是去猜一个「我本机恰好有」的目录。
129
+
130
+ ## 快速开始
131
+
132
+ ```bash
133
+ # 0) 让 Python 找得到 aaas 源码(未 pip install 时必需)。
134
+ # 注意:.aaas-src 只被 conftest.py / scripts 里的入口读取 —— `python -m aaas_service`
135
+ # 是标准模块入口,它只认 PYTHONPATH,不认那个文件(库不该偷偷改 sys.path)。
136
+ set "AAAS_SRC=D:\path\to\aaas\src"
137
+ set "PYTHONPATH=%AAAS_SRC%;."
138
+
139
+ # 1) 起服务(需要真实凭据;默认监听 127.0.0.1:8888)
140
+ set "DEEPSEEK_API_KEY=sk-..."
141
+ python -m aaas_service
142
+
143
+ # 2) 只想确认「这套环境最终会用什么」—— 不起服务、不联网、不要 key
144
+ python -m aaas_service --print-config
145
+
146
+ # 3) 交互式调用方(另开一个终端)
147
+ python scripts/chat.py
148
+ ```
149
+
150
+ 变量清单见 [`.env.example`](.env.example)(只有变量名,没有任何真实值)。
151
+ `--print-config` 的输出会把**每个值的来源**一起印出来(`--model` / `AAAS_MODEL` /
152
+ `内置默认` …),凭据只报变量名与长度、永不报值:
153
+
154
+ ```
155
+ 配置 provider=deepseek(--provider) model=deepseek-flash(内置默认)
156
+ base_url=https://api.deepseek.com(内置默认) api_key=DEEPSEEK_API_KEY(len=35)
157
+ ```
158
+
159
+ `python scripts/service_ctl.py start|status|stop|config` 是同一套装配的进程管理入口,
160
+ `status` 做的是一次**真正的协议握手**(端口开着只证明有人 listen,握手成功才证明
161
+ 对端是 aaas 且宣告的能力都在)。
162
+
163
+ ## 模型配置从哪来
164
+
165
+ 四个旋钮在**进程启动时**解析一次,调用方永远影响不了它们。顺序是一条规则,没有例外:
166
+
167
+ ```
168
+ 命令行参数(--provider / --model / --base-url / --api-key)
169
+ > AAAS_PROVIDER / AAAS_MODEL / AAAS_BASE_URL / AAAS_API_KEY
170
+ > 提供方约定变量(OPENAI_API_KEY、OPENAI_BASE_URL、DEEPSEEK_API_KEY …)
171
+ > 内置默认
172
+ ```
173
+
174
+ | 提供方 | 内置默认模型 | 默认地址 |
175
+ |---|---|---|
176
+ | `openai` | `gpt-4o-mini` | SDK 默认 |
177
+ | `deepseek` | `deepseek-flash` | `https://api.deepseek.com` |
178
+ | `dashscope` | `qwen-max` | dashscope 兼容端点 |
179
+ | `anthropic` | `claude-sonnet-4-5` | SDK 默认 |
180
+
181
+ **空值就是没设**:`set "VAR="` 留下的空变量不会顶掉默认值;`AAAS_SRC` 这类路径变量
182
+ 还会顺手剥掉误包的引号(`set VAR="C:\x"` 会把引号一起存进值里)。
183
+
184
+ ## 跑测试
185
+
186
+ ```bash
187
+ pip install -e ".[test]" # 含 agentscope / aaas / pytest / pytest-asyncio
188
+ python -m pytest tests -q # 全离线
189
+ set "AAAS_LIVE=1" && python -m pytest tests -q # 加上真调用的 live 用例(花钱)
190
+ ```
191
+
192
+ **`pytest-asyncio` 不是可选项**:`pytest.ini` 里的 `asyncio_mode = auto` 只有它认。
193
+ 少了它,所有 `async def test_*` 只会得到一条 warning 然后被**跳过** —— 一片绿色里
194
+ 十几个用例其实一次都没执行。这是本项目被评审点名过的坑,别踩第二次。
195
+
196
+ 单元与端到端都不联网:模型用脚本化的假模型替身,协议层跑真 WebSocket。
197
+
198
+ ## 改代码的流程(本仓库的硬规矩)
199
+
200
+ **任何代码改动都必须先过 `ocr`(open-code-review)再提交。** 它不是可选的唠叨,
201
+ 理由很实在:这个项目的坑大多长在「看起来没问题」的地方(未知 token 写成 0、
202
+ `None` 与默认值混淆、GBK 下的编码崩溃),人工评审很容易顺着作者的想法走。
203
+
204
+ ```bash
205
+ # 审「工作区改动」:staged + unstaged + untracked 全都要
206
+ ocr review
207
+
208
+ # 机器可读,便于逐条跟踪
209
+ ocr review --format json -o .tmp/review.json
210
+
211
+ # 没有 diff 也要审(例如初次引入一个模块)
212
+ ocr scan --path aaas_service,tests
213
+ ```
214
+
215
+ 评审意见的处理约定:
216
+
217
+ 1. **每条都要有结论**:采纳就改;不采纳就在 PR / 提交说明里写清为什么不采纳。
218
+ 「看到了但没管」不算结论。
219
+ 2. 改完**再跑一次**,直到没有阻塞项。
220
+ 3. `ocr` 的 LLM 配置属于个人环境(`ocr config`),**不进仓库**。
221
+
222
+ ## 发布
223
+
224
+ 版本号只有一个真源:`aaas_service/__init__.py` 的 `__version__`。
225
+ `pyproject.toml` 里**不写** version,构建时由 `[tool.setuptools.dynamic]` 取那个属性
226
+ (两份写死在早晚会漂移)。发布流程:
227
+
228
+ ```bash
229
+ # 1) 改 aaas_service/__init__.py 的 __version__
230
+ # 2) 改完代码先过 ocr(见下节),测试绿了再打包
231
+ python -m pytest tests -q
232
+ python -m build # 产出 dist/*.whl 与 dist/*.tar.gz
233
+ python -m twine check dist/* # 校验 README 能渲染、元数据完整
234
+ python -m twine upload dist/* # 需要 ~/.pypirc 里的 [pypi] token
235
+ ```
236
+
237
+ 两条硬规矩:
238
+
239
+ - **PyPI 上的版本号不可覆盖、不可删除重发。** 发坏了只能发下一个版本 ——
240
+ 所以 `twine check` 和「干净 venv 装一遍 wheel」不是可选项(这条我们真踩过)。
241
+ - **凭据只从 `~/.pypirc` / 环境变量来**,永不进仓库、永不进日志
242
+ (`--print-config` 只报变量名与长度,不报值)。
243
+
244
+ ## 相关文档
245
+
246
+ - [README-IMPLEMENTATION.md](README-IMPLEMENTATION.md) —— 实施细节、逐条实测、踩过的坑
247
+ - [PROPOSAL-aaas-agentscope.md](PROPOSAL-aaas-agentscope.md) —— 方案与协议事实核对
248
+ - [REVIEW-jev.md](REVIEW-jev.md) —— 关键设计判定的决策记录
249
+
250
+ ## License
251
+
252
+ [Apache-2.0](LICENSE)
253
+
254
+ ## 评审流程(ocr)
255
+
256
+ 本仓库的规矩:**改代码 → 过 `ocr` → 每条意见都有结论 → 才提交。**
257
+ 不是「建议」,是提交前的必要条件 —— 因为这套代码里最贵的 bug 都不是写错的,
258
+ 而是「看起来对、在边角上静默做错事」的那种。
259
+
260
+ ### 工具
261
+
262
+ [open-code-review](https://www.npmjs.com/package/open-code-review)(`ocr`,需要 Node):
263
+
264
+ ```bash
265
+ npm i -g open-code-review
266
+ ocr llm test # 先确认它自己能用(provider / model / key)
267
+ ocr review --format json -o .tmp/review.json --audience agent
268
+ ```
269
+
270
+ ### 三步,顺序不能变
271
+
272
+ ```bash
273
+ git add -A # ① 评审读的是 **git index**
274
+ ocr review --format json -o .tmp/review.json --audience agent # ② 跑评审
275
+ python -m pytest tests -q # ③ 改完必须仍然是绿的
276
+ ```
277
+
278
+ **① 是这条流程里最容易白烧钱的一步。** `ocr review` 看的是 index 里那份快照:
279
+ 改完不 `git add -A`,它评的还是改之前的代码(我们照着做时白跑过一整轮,
280
+ 40 条意见里 32 条是上一轮的重复)。
281
+
282
+ ### 每条意见都要有结论
283
+
284
+ 两类结论都算「有结论」,但**必须写出来**:
285
+
286
+ - **采纳** —— 改代码,并在 `tests/test_review_fixes.py` 里加一条回归测试
287
+ (每条测试的 docstring 点名它守的是哪个坑)。
288
+ - **驳回** —— 写下实测理由。本项目驳回过的三类,都是「意见本身不成立」:
289
+ `__main__` 改名(dunder 是本项目的命令行入口约定,`main` 会凭空多一个空参数工具)、
290
+ `--provider` 标注(子进程**真的**收到了这个参数,标注准确)、
291
+ `ctx.error = int`(实测 `aaas.TurnContext.error` 的类型是 `AAASError | None`)。
292
+
293
+ ### 本仓库的实际记录
294
+
295
+ | 轮次 | 意见数 | 最高级别 | 处理 |
296
+ |---|---|---|---|
297
+ | 1 | 39 | HIGH ×2 | 全采纳 |
298
+ | 2 | 40 | MEDIUM | 8 条真新问题(其余是 index 未刷新) |
299
+ | 3 | 19 | MEDIUM | 全采纳 |
300
+ | 4 | 20 | MEDIUM | 全采纳 |
301
+ | 5 | 17 | MEDIUM | 全采纳 |
302
+ | 6 | 23 | MEDIUM | 采纳 22 / 驳回 3 |
303
+ | 7 | 9 | HIGH ×1 | 全采纳(HIGH 是第 6 轮修复自己引入的回归) |
304
+ | 8 | 10 | MEDIUM ×1 | 全采纳 |
305
+ | 9 | 见下 | — | 发布准备(pyproject / 打包 / 发布流程) |
306
+
307
+ 一条经验:**第 7 轮那条 HIGH 是我自己修出来的**(引用了一个只存在于注释里的常量,
308
+ 于是诊断工具在「pid 文件过期」这种最常见的情况下自己崩了)。所以「改完就跑一遍」
309
+ 不是形式主义 —— 修复本身也会是新的 bug 源,而评审 + 回归测试是唯一能抓住它的东西。