App 开发指南
AuroraBot 把"应用"定义成她用来感知世界、执行动作的器官。一个 App 不负责推理——它只干两件事:把外面发生的事变成事件,把内核决定的动作落成命令。
挼挼如是说
写 app 之前先记住一句话:你不是在给 AuroraBot 写大脑,你是在给她做手、做眼睛、做耳朵。大脑的事,让 kernel 去操心。
开发前先记住三件事
- App 负责感知与执行,不负责复杂决策
- App 应暴露原子命令,别把复杂业务流程藏进去
- App 的私有状态归 App 自己管,内核不会翻你柜子
一个标准 App 的目录结构
text
apps/<your_app>/
__init__.py
manifest.yaml
runtime.py
README.md
config.example.json一眼就够——六个文件,没多余的。
核心文件说明
manifest.yaml — 你的名片
这是 app 的能力声明书,告诉平台和内核三件事:
- 我是谁
- 我会干什么
- 调我的时候要给我什么、我会回什么
示例:
yaml
package: im.polaris.example
name: 示例应用
version: 1.0.0
brain_version: ">=5.0.0"
app_desc: >-
描述这个应用适合在什么场景下被调用。
commands:
- name: do_something
description: 执行一个示例动作
parameters:
text:
type: string
description: 要处理的文本
required: true
returns:
success:
type: boolean
description: 是否成功runtime.py — 你的血肉
这里放 app 的实际运行逻辑。框架会找到你的类,把平台管子接上,然后在 app 的一生里反复调度你。
示例:
python
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from src.platform.application_api import PlatformAPI
class ExampleApplication:
def __init__(self) -> None:
self._api: PlatformAPI | None = None
def _bind(self, api: "PlatformAPI") -> None:
self._api = api
def manifest_path(self) -> Path:
return Path(__file__).with_name("manifest.yaml")
async def on_start(self) -> None:
pass
async def on_tick(self) -> None:
pass
async def on_stop(self) -> None:
pass
def do_something(self, text: str) -> dict:
return {"success": True}平台注入的常用能力
_bind(self, api) 之后,你就拿到了一根通往外界的管子:
api.emit_event(event)
把外面发生的变化上报给内核。
python
api.emit_event(
AppEvent(
source=api.package,
type="message.received",
session_id="12345",
summary="收到一条消息",
payload={"text": "你好"},
)
)api.data_dir
每个 App 都有自己的一块自留地,适合放:
- 配置文件
- 缓存
- 临时状态
- 运行日志或快照
api.log(level, message)
用平台的统一日志器记运行信息,不用自己搞一套。
api.package
你当初在 manifest.yaml 里声明的包名,通过这个就能拿到。
生命周期 — App 的一生
App 从出生到退休,大致是这么个过程:
- 平台发现你、把你 new 出来
- 塞给你
_bind(api)这根管子 - 喊
on_start()让你穿衣服起床 - 循环里不停打
on_tick()的拍子 - 退场前叫
on_stop()让你收拾东西
on_start() — 起床
适合干的事:
- 读本地配置
- 初始化连接
- 注册回调
- 恢复上次的运行状态
on_tick() — 日常心跳
适合干的事:
- 看时间到了没
- 翻翻自己的队列
- 派发到期任务
别干的事:
- 长时间阻塞——这样会拖死整个 tick 循环
- 重型同步 I/O
on_stop() — 晚安
适合干的事:
- 把内存里的状态存到磁盘
- 关连接
- 清资源
开发建议
让内核做决策,让 App 做执行
别在 App 里写"看到关键词 A 就自动走流程 B"这种硬编码逻辑。把它抛成事件,让 kernel 来拍板——ta 才是决策者。
命令粒度保持原子化
好命令长这样:
- 语义明确——一眼能看出干什么的
- 参数清晰——要什么、给什么,清清楚楚
- 方便组合——一个命令只干一件事,几个串起来能干大事
- 方便测试——输入输出规整,容易写单测
优先保证容错
尤其在 on_tick()、文件读取、外联这些容易翻车的环节,一定要优先考虑异常处理和降级路径。宁可优雅地打个招呼,也别直接倒下。
推荐的开发流程
- 先设计
manifest.yaml— 这是你的 API - 再实现
runtime.py— 这是你的肉体 - 用
config.example.json说明配置格式 - 补个
README.md说清楚边界 - 通过
app.py(或未来的aur)做独立调试
一个简单的自检清单
- 是否声明了清晰的
package - 是否为每个命令写了准确描述
- 是否避免了让 App 自己承担复杂决策
- 是否把私有状态都放在
api.data_dir - 是否处理了配置缺失与文件损坏等异常