01概览与模块
SDK 按「客户端 / 运行时 / 界面 / 能力 / 物料」五类切分,按需组合:最小集成只需 sdk-runtime,要现成设置页加 sdk-ui,要屏幕、浏览器、语音等能力再按需引入对应 capability 模块。
| Module | 形态 / 职责 |
|---|---|
| sdk-client | KMP(commonMain 零 Android 类型,iOS 预留)。qwen serve 协议类型化客户端:会话 / prompt / SSE→Flow / MCP / 技能 / 设置 / 预热 / transcript 恢复。 |
| sdk-runtime | Android AAR。物料铺设、init 编排、proot 启动、serve 生命周期与后台保活;Service 运行于 :runtime 独立进程,与 UI 崩溃隔离。 |
| sdk-ui | Compose 设置页(模型·密钥·语音·MCP·技能开关),可选挂入宿主导航。 |
| sdk-capability-screen可选 | 屏幕感知/操控:无障碍服务 + A11yHttpServer + device-screen MCP。 |
| sdk-capability-browser可选 | 可见浏览器:专用 WebView + CDP 中继 + 覆盖层 + 跨站重建链。 |
| sdk-capability-voice可选 | 语音输入 ASR 三协议桥。 |
| sdk-capability-fileopen可选 | 系统应用打开文件(FileProvider;JNI keep 规则随 AAR 分发)。 |
| sdk-assets | OSS 物料包(不入 git,仅 SHA256SUMS 指针):bootstrap rootfs / debs / python / npm 引擎 / skills / mcp / init.sh。 |
02环境要求
- minSdk 28(Android 9.0)、compileSdk 36、targetSdk 建议 36。
- Kotlin 2.1.21+、AGP 8.11.0+、JDK 17。
- 使用
sdk-ui时需 Compose,推荐 BOM2025.08.00。 - 设备架构 arm64(物料按 aarch64 分发);无需 root。
03接入步骤
3.1 依赖
// build.gradle.kts implementation("com.jvscopilot.agentruntime:sdk-runtime:0.1.1") implementation("com.jvscopilot.agentruntime:sdk-ui:0.1.1") // 可选:现成设置页 implementation("com.jvscopilot.agentruntime:sdk-capability-screen:0.1.1") // 可选,按需
开发期推荐 composite build:把坐标替换为本地工程,SDK 改动即时生效、免 publish。
// settings.gradle.kts(开发期) includeBuild("../agent-runtime-sdk") { dependencySubstitution { substitute(module("com.jvscopilot.agentruntime:sdk-runtime")).using(project(":sdk-runtime")) substitute(module("com.jvscopilot.agentruntime:sdk-ui")).using(project(":sdk-ui")) } }
3.2 入口与初始化门闸
AgentRuntime.get(context) 是唯一入口;initialize() 返回状态流,覆盖「物料铺设 → init 幂等编排 → proot 启动 → serve 就绪」全过程。进入主界面前必须消费该流。
val runtime = AgentRuntime.get(context) lifecycleScope.launch { runtime.initialize().collect { state -> when (state) { is RuntimeState.Initializing -> showProgress(state.stepIndex, state.stepTotal, state.firstInstall) RuntimeState.Running -> enterHome() is RuntimeState.Failed -> showDiag(runtime.readRuntimeErrorReport()) // runtime-error.json 五字段 else -> Unit // NotStarted } } }
文案纪律:
Initializing.step 是 SDK 内部步骤名,不要直接展示给用户;面向用户的进度请用 stepIndex / stepTotal(「第几步 / 共几步」)。firstInstall = false 表示设备已完成过初始化(升级重铺物料),避免误用「首次安装」类文案。3.3 会话与流式 prompt
val client = runtime.client // serve 就绪后可用 val session = client.createSession(title = "新会话") // 事件流:SSE→Flow,先订阅再发 prompt launch { client.events(session.id).collect { event -> render(event) } } client.prompt(session.id, text) // 退避重试内建;404→resume 链 // 中止:client.abortSession(session.id)
内建机制,无需自实现:建会话强制 thread scope(防预热会话混线);
events() 懒建流,仅活跃会话自动恢复;prompt 连接退避 5 次(1/2/4/8/8s)。3.4 提问应答与附件(可选)
- Agent 发起
ask_user_question时,用answerQuestion(sessionId, requestId, answers)提交(键为题目 0-based 序号字符串,值为选中 label);取消走cancelQuestion。 - 附件必须先经
runtime.attachments.importAttachment()落盘,拿到PromptAttachment后再prompt(sessionId, text, attachments);未落盘即发,模型读到空。
3.5 现成设置页(可选)
// Compose 导航中挂入 AgentSettingsScreen( runtime = runtime, developerExtras = myPanels, // 宿主自定义面板 featureToggles = myToggles, // 宿主功能开关 hiddenMcpServers = setOf("edu-classroom"), )
覆盖模型与密钥、语音、MCP 开关、技能清单;宿主面板与开关以参数注入,不必 fork SDK。
3.6 能力模块(可选)
| 能力 | 集成方需要做什么 |
|---|---|
| screen | 引导用户开启无障碍服务(读屏);点击/输入/滑动默认关闭,由宿主显式打开。 |
| browser | 无额外权限;浏览器 UI 由 SDK 提供,宿主仅触发打开。 |
| voice | 运行时请求麦克风权限;ASR 目标经 resolveVoiceTarget() 解析,无可用目标时语音按钮不渲染。 |
| fileopen | 零配置;路径翻译必须取自 runtime.workspace,不要自行拼接 guest 路径。 |
04进程与运行时模型
- 双进程:UI 进程持有 Compose 与业务;
:runtime独立进程由RuntimeEngineService承载 proot、serve 与全部 Node 子进程。UI 崩溃不拖垮运行时,运行时崩溃不拖垮 UI。 - 杀 UI 进程后 serve 存活:watchdog 与收养幂等内建,重进 App 自动接回。
- 边界:proot、serve 端口、serve-token 均为 SDK 私产;
runtime.client的 baseUrl 由本地代理注入,令牌不外泄。宿主代码中不应出现端口号或 guest 路径字面量。 - 停止:
runtime.shutdown()按 serve → proot 子树 → 前台服务顺序回收。
05保活与权限
sdk-runtime 清单已声明并合并以下权限;前台服务类型为 mediaPlayback(国产 ROM 后台存活实证最优),通知文案与图标由宿主注入。
INTERNET / FOREGROUND_SERVICE / FOREGROUND_SERVICE_MEDIA_PLAYBACK
WAKE_LOCK / ACCESS_NETWORK_STATE / POST_NOTIFICATIONS
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS // 电池优化白名单引导- 四层保活防线的状态检查与引导 Intent 经
runtime.keepAlive.requirements()暴露;引导页面由宿主渲染(如电池优化白名单、自启动管理)。 - 本地代理与 serve 均为 127.0.0.1 明文 HTTP;宿主若自设
networkSecurityConfig,以宿主为准(library 清单低优先级,静默覆盖)。
06物料与更新
- 物料经 OSS 分发,SHA256 MANIFEST 逐项校验后释放;init 编排幂等,中断可断点续做。
- 升级时自动重铺物料并自愈对齐;
Initializing.firstInstall = false即该场景。 - SDK 版本(根 build 单源,宿主关于页经 BuildConfig 自动跟随)与物料版本两轨独立递增,互不绑架。
- 诊断:
readRuntimeErrorReport()读 runtime-error.json 五字段;readInitProgress()读 init 进度原文。
07API 一览
AgentClient 为纯 Kotlin 协程接口(suspend / Flow),KMP commonMain,零 Android 类型。
生命周期
- awaitReady()等待 serve 就绪,discovery 空窗内建重试
- serveReady(): Flow<Unit>「不可达→可达」跃变广播,供自愈重拉
- runtimeState(): Flow<RuntimeState>初始化进度 / 运行中 / 异常
会话
- createSession(title?)thread scope 强制内建,防混线
- listSessions()封套 / 裸数组双兼容;懒建流
- deleteSession(id)归档语义:转录移 archive,列表不再返回
- renameSession(id, name)进程内存语义,跨重启持久化归 App 层
事件流 & prompt
- events(sessionId): Flow<AgentEvent>SSE→Flow;仅活跃会话自动恢复
- prompt(sessionId, text, attachments)退避重试内建;404→resume 链
- abortSession(id)中止进行中 turn
- answerQuestion / cancelQuestionask_user_question 应答与取消
MCP
- mcpStates(): Flow<List<McpServerState>>connected / connecting / disabled
- setMcpEnabled(server, enabled)官方路由优先,回落写 settings
- addMcpServer / updateMcpServer / removeMcpServer落盘先、REST 条件性后
- importMcpServers / previewImportMcpServers / exportMcpServer批量导入预览与导出
- warmupMcpConnections(previousId?)隐藏 thread 预热,id 由 App 持久化与过滤
设置 & 模型目录
- getSettings() / setModel(provider, model, overrides?)settings.json 类型化投影
- setSessionModel / sessionModelOverride / writeSessionModelOverride会话级模型覆写
- refreshModelCatalog() / readModelCatalog()动态目录并集合并 / 纯文件投影
- listEduProviders / setApiKey / addCustomProvider / removeCustomProvider提供商与密钥(加密存储)
- setVoiceInputService / resolveVoiceTarget()语音 ASR 选择与目标解析
技能 · 工作区 · 诊断
- listSkills()serve 只读投影;写路径走 runtime.skills
- runtime.workspace / runtime.attachments文件列举、路径翻译、附件落盘
- restoreTranscript(sessionId)磁盘 jsonl 重建,含 tool part
- serveLogs(lines) / execDebugCommand(cmd)运行状态面板数据源(白名单强制)
- close()释放 SSE 与协程域,实例不可再用
08构建与混淆
- R8:无需额外规则;
capability-fileopen的 JNI 反射面 keep 规则随 AAR 的 consumer rules 分发,随包免疫。 - 明文:仅 127.0.0.1 本地通信使用 cleartext;对外网络全部走宿主自己的 HTTPS 栈。
- KMP:sdk-client 位于 commonMain,零 Android 类型,iOS 目标预留;宿主无需关心平台分支。
- 清单合并:sdk-runtime 的 service / 权限声明随 AAR 合并;宿主同名配置优先级更高,不产生冲突。
09常见问题
- 冷启动要多久?首装需释放并校验物料,进度经
Initializing可见;非首装为秒级。discovery 空窗(t≈5–12s)已由awaitReady内建重试吸收。 - 初始化 Failed 怎么办?读
readRuntimeErrorReport()取五字段诊断(含 diagnosticsPath),按报告指引修复后重新initialize();init 幂等,可断点续做。 - 删除会话为何不是物理删除?
deleteSession是归档语义(转录移入 archive),保证可审计与误删可恢复;幂等,重复删除不报错。 - 重命名重启后丢了?
renameSession为进程内存语义,跨重启持久化归 App 层,重启后以持久化值重放一次即可。 - 会话列表里有幽灵会话?预热会话由
warmupMcpConnections产生,id 返回给 App;请在 UI 过滤并持久化该 id,下次调用传回previousId。 - 能在主线程调用吗?全部为 suspend / Flow,请在协程域(viewModelScope / lifecycleScope)消费;不要在主线程阻塞等待。
10版本与支持
- 当前版本 0.1.1;版本号在 SDK 根 build 单源维护,宿主关于页经
BuildConfig.SDK_VERSION自动跟随。 - 现阶段以 composite build / publishToMavenLocal 分发;私有仓库坐标与集成支持随接入开通提供。
- 行为规格以仓库内 spec 文档为准(A1-QwenAndroid/agent-runtime-sdk-native-android.md);本文档与其冲突时以 spec 为准。