跳到正文

参考

适配器接口

BodyAdapter、RawSample、AdapterTool、Hands 的完整类型,加载方式与约束,以及 Termux 适配器的能力清单。

#类型

定义在 runtime/src/body/adapter.ts。适配器是一个独立构建的 ES 模块,默认导出一个 BodyAdapter。

typescript
/** 一次物理采样。字段全部可选:设备有什么就报什么。 */
interface RawSample {
  battery?: { level: number; charging: boolean; tempC?: number; health?: string };
  lux?: number;      // 环境光照
  motion?: number;   // 加速度偏离重力的幅度(m/s²)
  screenOn?: boolean;
  extra?: Record<string, string | number | boolean>;  // 设备特有读数,原样进入孪生
}

/** 适配器提供给 agent 的工具(动作)。handler 返回给模型看的文本。 */
interface AdapterTool {
  name: string;
  description: string;
  parameters: Record<string, unknown>;   // JSON Schema
  permission: string;                    // 闸门的能力类别:device、camera、microphone、location…
  handler: (args: Record<string, any>) => Promise<string>;
}

/** 预留:操控屏幕与其他应用。 */
interface Hands {
  screenshot(): Promise<string>;         // 返回图片路径
  describeScreen(): Promise<string>;
  tap(x: number, y: number): Promise<void>;
  swipe(x1: number, y1: number, x2: number, y2: number): Promise<void>;
  type(text: string): Promise<void>;
  openApp(id: string): Promise<void>;
}

interface BodyAdapter {
  name: string;
  describe: string;                      // 一句话描述这具身体,写进 agent 的自我认知
  init?(): Promise<void>;
  sample(): Promise<RawSample>;
  notify?(title: string, text: string): Promise<void>;   // 本地系统通知
  speak?(text: string): Promise<void>;
  playAudio?(file: string): Promise<void>;               // 播放音频文件(语音合成的结果)
  tools?: AdapterTool[];
  hands?: Hands;
}

#加载

来源说明
环境变量 QUETZAL_ADAPTER模块路径(Termux 部署用这个)
配置 adapterconfig/quetzal.json 里的路径
都没有 / 加载失败回退到通用适配器 generic(无传感器,sample() 返回空对象)

#约束

  • 适配器只能 import type 接口文件的类型,不得依赖核心的其他实现。
  • tools[].permission 必须是闸门已知的能力类别,否则按「允许」处理。
  • notify 是配对码与主动消息的本地出口;没有它,配对码只能从 secrets/gateway.token 读。

#采样如何使用

  • startSenses 周期调用 sample(),间隔自适应 2–10 分钟,不调用模型。
  • 读数与操作系统信息一起进入身体孪生,派生身体感受,与上次比较产生 sense 事件,影响驱动力并触发重新抽样。
  • extra 原样进入 ta 看到的「身体」段落。

#Termux 适配器(runtime/adapters/termux/,构建为 dist/termux.mjs)

能力实现
sample()termux-battery-status(电量 / 充电 / 体温 / 健康)、termux-sensor(光照与运动,传感器按名字探测,没有就不报)
notify()系统通知,带「打开 Quetzal」按钮(QUETZAL_CONSOLE_ACTIVITY,默认 xyz.quetzal.console/.MainActivity)
playAudio()termux-media-player
工具take_photo(camera)、record_audio(microphone)、location(location)、vibrate / torch / clipboard / read_sensor(device)
speak不提供(很多手机没有系统 TTS);说话由运行基座的 voice_speak 完成
媒体位置QUETZAL_HOME/data/media/

它是平台级适配器:任意安卓手机 + Termux:API,一切靠探测,不含任何具体机型的实现。

#Linux 适配器(runtime/adapters/linux/,构建为 dist/linux.mjs)

随 npm 包 @plutokeating/quetzal 安装(npx @plutokeating/quetzal),同样是平台级:任意 Linux 电脑或服务器,一切靠探测。

能力实现
sample()/sys/class/power_supply:电量 / 充电 / 健康(跳过蓝牙鼠标等外设电池;「Not charging」且外接电源在线算充电),电池自身温度(temp,笔记本少有);extra:CPU 温度(/sys/class/thermal,不当作体温)、电源来源。台式机与服务器没有电池就只有 extra
describe发行版(/etc/os-release)、是否笔记本、有没有桌面、摄像头(/dev/video0)与声卡(/proc/asound/cards)
notify()有桌面时 notify-send;同时写到标准输出(服务日志),没有桌面的机器从 quetzal logs 看配对码
playAudio() / stopAudio()pw-play / paplay / ffplay / mpv,WAV 还可 aplay;后台播放,立即返回
工具take_photo(camera:ffmpeg 读 /dev/video0)、record_audio(microphone:arecord / pw-record / parecord / ffmpeg,WAV)、screenshot(hands:Wayland 下 grim / gnome-screenshot / spectacle,X11 下 scrot / gnome-screenshot / spectacle / import)、clipboard(device:wl-clipboard / xclip / xsel)、open(device:xdg-open)
speak不提供;说话由运行基座的 voice_speak 完成
媒体位置QUETZAL_HOME/data/media/

没有图形界面的服务器上,截图、剪贴板、打开网址这些工具会直接说明「这台电脑没有图形界面」,不报错。写一个新适配器见 自定义身体适配器。