From fe5aaccb5b216f5ebdc89bd4fd590a796e28b6e8 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:09:33 -0700 Subject: [PATCH 1/6] docs: walk through app hosting, agent interactions and Tokio execution --- AGENTS.md | 12 ++ README.md | 10 +- README.zh-CN.md | 10 +- apps/AGENTS.md | 21 +- apps/README.md | 10 + apps/README.zh-CN.md | 8 + apps/appcard/AGENTS.md | 8 + apps/appcard/README.md | 12 +- apps/appcard/README.zh-CN.md | 9 +- crates/kernel/README.md | 6 +- crates/kernel/README.zh-CN.md | 4 +- desktop/AGENTS.md | 18 ++ desktop/README.md | 4 +- desktop/README.zh-CN.md | 4 +- desktop/docs/code-walkthrough.md | 281 +++++++++++++++++++++++++ desktop/docs/code-walkthrough.zh-CN.md | 147 +++++++++++++ docs/ai-services.md | 67 +++--- docs/ai-services.zh-CN.md | 79 +++---- docs/architecture-walkthrough.md | 223 ++++++++++++++++++++ docs/architecture-walkthrough.zh-CN.md | 169 +++++++++++++++ docs/architecture.md | 13 +- docs/architecture.zh-CN.md | 13 +- phone/AGENTS.md | 24 +++ phone/README.md | 4 +- phone/README.zh-CN.md | 4 +- phone/android/README.md | 15 +- phone/android/README.zh-CN.md | 10 +- rom/AGENTS.md | 19 ++ rom/README.md | 2 + rom/README.zh-CN.md | 2 + 30 files changed, 1099 insertions(+), 109 deletions(-) create mode 100644 desktop/AGENTS.md create mode 100644 desktop/docs/code-walkthrough.md create mode 100644 desktop/docs/code-walkthrough.zh-CN.md create mode 100644 docs/architecture-walkthrough.md create mode 100644 docs/architecture-walkthrough.zh-CN.md create mode 100644 phone/AGENTS.md create mode 100644 rom/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md index 5d790b9c..5b92a9cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,3 +49,15 @@ On a machine that already has clones of Makepad, OctoScript or Octoscript-Makepa 8. **Commit with a public identity.** Author and committer are your GitHub noreply address (for the maintainer, `ymote <151983+ymote@users.noreply.github.com>`) or another address you mean to publish; never a work or machine-local address. Check `git config user.email` before the first commit in a clone: a repository-local identity on a shared machine leaked a work address into this project's history once, and removing it took a history rewrite. 9. **Keep docs honest and bilingual.** Every command in a doc was run; anything not run is marked **unverified**. User-facing docs are `README.md` plus `README.zh-CN.md`, linked by the single switcher line under the title (`English | [简体中文](README.zh-CN.md)`), and change together. `AGENTS.md` files are English only. 10. **Keep signing keys, keystores, tokens and personal paths out of the repository.** `rom/tests/test_no_local_paths.py` checks for local paths. + +## Architecture documentation and code walkthroughs + +For an unfamiliar subsystem, start with [the junior-Rust walkthrough](docs/architecture-walkthrough.md) and [the product walkthrough](desktop/docs/code-walkthrough.md), then follow their source symbols. Keep the English/Chinese guides and README entry points aligned when a boundary changes. + +- Trace the checked-out implementation and the root Cargo/runtime pins. Do not mix old `home/` worktrees or archived System-Apps/AppCard repositories into current product instructions. +- Separate application hosting (Rust module/process, contained Splash app, L0 card) from agent identity (peer/session/context) and execution (UI thread, worker thread, Tokio task/runtime). +- When documenting an app operation, verify its manifest, admitted `tools.json`, grant and executable handler. A UI host-service API, `shareable` flag or accepted `AGENT.md`/trigger file does not prove an agent can execute it. +- Distinguish an app account workspace, host-service database, kernel memory and host secrets. Check accountless `device` and signed-in account paths separately. +- Keep human conversation contexts distinct from the system-lane peer session; never describe all app instances as independent peers or all peers as one task each. +- Check cross-app claims at both App Hub admission (`HostLimits.offered_tools`) and the shell relay. A route supported by the relay can still be rejected at admission. +- Report unit/scripted-connector tests separately from optional real-kernel suites that early-return without binary environment variables. Mark unrun UI, provider, mobile and ROM commands unverified. diff --git a/README.md b/README.md index 9624d840..8d00b37b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ English | [简体中文](README.zh-CN.md) -[OctoSense](https://github.com/OctoSense-org) is an agent shell on top of your operating system: a launcher and apps that look like the ones you know, with one agent behind them. This repository holds all of OctoSense's own code in one place ([ADR 0001](docs/adr/0001-one-octosense-repository.md)): the shell, its services, the first-party system apps, and the three products built from them. +[OctoSense](https://github.com/OctoSense-org) is an agent shell on top of your operating system: a launcher and apps that look like the ones you know, with a system agent coordinating app agents. This repository holds all of OctoSense's own code in one place ([ADR 0001](docs/adr/0001-one-octosense-repository.md)): the shell, its services, the first-party system apps, and the three products built from them. | Product | What it is | Where | | --- | --- | --- | @@ -14,6 +14,10 @@ It was OctoSense-Desktop; OctoSense-ROM (retired; merged into this repository) a > **Building an OctoSense app?** You do not need this repository to build, check or publish one. Start at the [OctoSense-org profile](https://github.com/OctoSense-org)'s reading list: [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow) (`AGENTS.md`, then `docs/QUICKSTART.md`) and [OctoSense-App-Hub](https://github.com/OctoSense-org/OctoSense-App-Hub). The system apps in [`apps/`](apps/README.md) are complete examples of the same app shape (`apps//bundle/`). Build the desktop shell from here only to see your app in a shell before it is published ([PUBLISHING §4](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/PUBLISHING.md#4-rehearse-the-store-path-locally)). +## Start with the code walkthrough + +For junior Rust developers, [From an app window to an agent turn](docs/architecture-walkthrough.md) follows executable entry points, native and script hosting, app data access, human/system conversations, tool routing and the actual Tokio tasks. The [product walkthrough](desktop/docs/code-walkthrough.md) adds desktop, Home, ROM and system-app run recipes. These guides distinguish source inspection, executed checks and unverified device/model runs. + ## How it fits together One shell process per device, one octos kernel per shell, and every agent is a session in that kernel. Apps never talk to the kernel: every path into octos goes through the shell, which holds the host connection and the host token, relays every agent tool call to the app that owns the tool, and puts every approval in front of the person. The full picture, with the code paths and what is on `main` versus planned: [docs/architecture.md](docs/architecture.md); the decisions: [ADR 0004](docs/adr/0004-native-apps-hosting-and-peers.md). @@ -90,7 +94,7 @@ flowchart LR | Mail (`os.mail`) | `apps/mail/bundle/tools.json`, the manifest's `agent` block and `glance` | `mail.notify` (the `mail` host service) | a notice card with a notification | | Calendar (`os.calendar`, desktop only) | `apps/calendar/bundle/tools.json`, the manifest's `agent` block and `glance` | `calendar.events`, `calendar.add_event`, `calendar.remove_event` (destructive: the person approves it), `calendar.notify`, `calendar.agenda` (the `calendar` host service) | an event card or an agenda card, with a notification | -A script app has an agent when its manifest declares `octos.*` names or an `agent` block (`"tools": ["ask_user_question"]` names the kernel tools it may use), or its bundle ships `tools.json` (each tool `.` with its schemas, `risk`, `confirm` and `shareable`). Its peer is `card.`. The person allows the agent once, on the first-use sheet (from the shell's "Ask " panel, the app's own `octos` call or the system agent's `agents.ask`). From then on the shell prepares the peer at startup, with the app's tools registered, so the system agent's `peer_list` shows it. Besides its own tools, an app agent gets the host read tools `files.list`, `files.read` and `files.search` over its account folder. On the phone, which builds `toolbox-peers` by default, it also gets the system toolbox's tools when its manifest asks for `research` or `crawl`, which no app does yet. `AGENT.md`, skills and triggers ([ADR 0002](docs/adr/0002-event-driven-app-agents.md)) are not built: an app agent runs only when the system agent, the person or a card asks it. +A script app has an agent when its manifest declares `octos.*` names or an `agent` block (`"tools": ["ask_user_question"]` names the kernel tools it may use), or its bundle ships `tools.json` (each tool `.` with its schemas, `risk`, `confirm` and `shareable`). Its peer is `card.`. The person allows the agent once, on the first-use sheet (from the shell's "Ask " panel, the app's own `octos` call or the system agent's `agents.ask`). From then on the shell prepares the peer at startup, with the app's tools registered, so the system agent's `peer_list` shows it. On Unix, a consented app agent with an available workspace also gets the host read tools `files.list`, `files.read` and `files.search` over its account folder; these do not expose every host-service database. On the phone, which builds `toolbox-peers` by default, it also gets the system toolbox's tools when its manifest asks for `research` or `crawl`, which no app does yet. `AGENT.md`, skills and triggers ([ADR 0002](docs/adr/0002-event-driven-app-agents.md)) are not built: an app agent runs only when the system agent, the person or a card asks it. **From the system agent to a card on the glance screen**: @@ -275,7 +279,7 @@ Related, not build inputs: [OctoScript-App-Design-Flow](https://github.com/OctoS Each shell runs one [octos](https://github.com/octos-org/octos) agent kernel, started on first use: the APK's `liboctos.so` on Android, in process on OpenHarmony, the binary `OCTOS_APP_CORE_BIN` names on a desktop, none on iOS. The person chooses its models and types keys in the **AI providers** system app, on host sheets; keys stay in the platform's secret store and never reach an app. [`crates/ai-host`](crates/ai-host/README.md) is the shells' one entry point, and [`crates/app-peers`](crates/app-peers/README.md) gives each granted native app its own octos peer (private contexts, workspace and memory `app//acct-`), owned by the shell's system agent. A peer's tool approvals are answered only by the person, in that app; the system agent cannot answer them. -What works today: native modules (Rinx) use their peer; AppCard (opt-in) uses the kernel directly. Contained script apps, system or store, reach it through the `octos` host service in a shell that hosts a kernel: each app gets its own host-owned peer (`card.`), and its tool approvals go to the shell's approval sheets like every other app agent's ([#155](https://github.com/OctoSense-org/OctoSense/pull/155)). The `llm` service manages providers for `os.*` apps only. An app's own agent (`tools.json`, `AGENT.md`, skills, triggers, glance cards) is [ADR 0002](docs/adr/0002-event-driven-app-agents.md); apps' `tools.json` tools reach their agents end to end since [#160](https://github.com/OctoSense-org/OctoSense/pull/160). +What works today: native modules (Rinx) use their peer; AppCard (opt-in) uses the kernel directly. Contained script apps, system or store, reach it through the `octos` host service in a shell that hosts a kernel: each app gets its own host-owned peer (`card.`), and its tool approvals go to the shell's approval sheets like every other app agent's ([#155](https://github.com/OctoSense-org/OctoSense/pull/155)). The `llm` service manages providers for `os.*` apps only. An app's own agent (`tools.json`, `AGENT.md`, skills, triggers, glance cards) is [ADR 0002](docs/adr/0002-event-driven-app-agents.md); host-service-backed `tools.json` tools reach their agents through the shell relay since [#160](https://github.com/OctoSense-org/OctoSense/pull/160). Tools marked `implemented_by: "app"` still lack a Card-runner executor; declaring a tool does not implement it. The architecture, the trust model, what each kind of app can use, the plan with its status, and how to run and test it locally: [docs/ai-services.md](docs/ai-services.md). How it fits into the whole system: [docs/architecture.md](docs/architecture.md). For app developers: OctoScript-App-Design-Flow's [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md). diff --git a/README.zh-CN.md b/README.zh-CN.md index 8b735c1c..82c04b15 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -2,7 +2,7 @@ [English](README.md) | 简体中文 -[OctoSense](https://github.com/OctoSense-org) 是运行在操作系统之上的 Agent 交互 Shell:启动器和应用看起来与你熟悉的一样,背后是同一个 Agent。本仓库集中存放 OctoSense 自己的全部代码([ADR 0001(英文)](docs/adr/0001-one-octosense-repository.md)):Shell、Shell 服务、第一方系统应用,以及由它们构建的三个产品。 +[OctoSense](https://github.com/OctoSense-org) 是运行在操作系统之上的 Agent 交互 Shell:启动器和应用看起来与你熟悉的一样,背后由系统 Agent 协调各应用 Agent。本仓库集中存放 OctoSense 自己的全部代码([ADR 0001(英文)](docs/adr/0001-one-octosense-repository.md)):Shell、Shell 服务、第一方系统应用,以及由它们构建的三个产品。 | 产品 | 是什么 | 位置 | | --- | --- | --- | @@ -14,6 +14,10 @@ > **要开发 OctoSense 应用?** 开发、检查或发布应用都不需要本仓库。请从 [OctoSense-org 主页](https://github.com/OctoSense-org)的阅读列表开始:[OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow)(先读 `AGENTS.md`,再读 `docs/QUICKSTART.md`)和 [OctoSense-App-Hub](https://github.com/OctoSense-org/OctoSense-App-Hub)。[`apps/`](apps/README.zh-CN.md) 中的系统应用是同样应用结构的完整示例(`apps//bundle/`)。只有想在发布前先在 Shell 里看到自己的应用时,才需要从这里构建桌面端 Shell([PUBLISHING §4](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/PUBLISHING.md#4-rehearse-the-store-path-locally))。 +## 从代码导读开始 + +面向 Rust 初学者的[从应用窗口到 Agent 回合](docs/architecture-walkthrough.zh-CN.md),沿着入口、原生/脚本托管、数据访问、人类/系统对话、工具路由以及实际 Tokio 任务阅读源码。[产品导读](desktop/docs/code-walkthrough.zh-CN.md)补充桌面、Home、ROM 和系统应用的运行方式,明确区分源码核对、已执行检查和未验证的设备/模型运行。 + ## 整体如何运作 每台设备一个 Shell 进程,每个 Shell 一个 octos 内核,每个 Agent 都是这个内核中的一个会话。应用从不直接与内核通信:进入 octos 的每条路径都经过 Shell。Shell 持有宿主连接和宿主 token,把每个 Agent 工具调用转交给拥有该工具的应用,并把每个审批交给用户。完整说明,包括代码路径以及哪些已在 `main` 上、哪些还在规划中:[docs/architecture.zh-CN.md](docs/architecture.zh-CN.md);相关决策:[ADR 0004(英文)](docs/adr/0004-native-apps-hosting-and-peers.md)。 @@ -90,7 +94,7 @@ flowchart LR | 邮件(`os.mail`) | `apps/mail/bundle/tools.json`、manifest 中的 `agent` 块和 `glance` | `mail.notify`(`mail` 宿主服务) | 一张通知卡片,并发出一条通知 | | 日历(`os.calendar`,仅桌面端) | `apps/calendar/bundle/tools.json`、manifest 中的 `agent` 块和 `glance` | `calendar.events`、`calendar.add_event`、`calendar.remove_event`(破坏性操作:由用户批准)、`calendar.notify`、`calendar.agenda`(`calendar` 宿主服务) | 一张日程卡片或议程卡片,并发出一条通知 | -脚本应用在以下情况下拥有 Agent:manifest 声明了 `octos.*` 名称或 `agent` 块(`"tools": ["ask_user_question"]` 列出它可以使用的内核工具),或者应用包附带 `tools.json`(每个工具名为 `.`,带 schema、`risk`、`confirm` 和 `shareable`)。它的 peer 是 `card.<应用 id>`。用户只需在首次使用面板上允许一次(从 Shell 的 “Ask ” 面板、应用自己的 `octos` 调用,或系统 Agent 的 `agents.ask` 打开)。此后 Shell 在启动时就准备好这个 peer 并注册应用的工具,所以系统 Agent 的 `peer_list` 能看到它。除了自己的工具,应用 Agent 还能用宿主的只读工具 `files.list`、`files.read` 和 `files.search` 读取其账号文件夹。手机默认构建 `toolbox-peers`,因此在手机上,manifest 申请了 `research` 或 `crawl` 的应用 Agent 还会得到系统工具箱的工具;目前还没有应用申请。`AGENT.md`、技能和触发器([ADR 0002(英文)](docs/adr/0002-event-driven-app-agents.md))尚未实现:应用 Agent 只在系统 Agent、用户或卡片请求时运行。 +脚本应用在以下情况下拥有 Agent:manifest 声明了 `octos.*` 名称或 `agent` 块(`"tools": ["ask_user_question"]` 列出它可以使用的内核工具),或者应用包附带 `tools.json`(每个工具名为 `.`,带 schema、`risk`、`confirm` 和 `shareable`)。它的 peer 是 `card.<应用 id>`。用户只需在首次使用面板上允许一次(从 Shell 的 “Ask ” 面板、应用自己的 `octos` 调用,或系统 Agent 的 `agents.ask` 打开)。此后 Shell 在启动时就准备好这个 peer 并注册应用的工具,所以系统 Agent 的 `peer_list` 能看到它。在 Unix 上,已获同意且有可用 workspace 的应用 Agent 还能用宿主只读工具 `files.list`、`files.read` 和 `files.search` 读取账号文件夹;这些工具不会暴露所有宿主服务数据库。手机默认构建 `toolbox-peers`,因此在手机上,manifest 申请了 `research` 或 `crawl` 的应用 Agent 还会得到系统工具箱的工具;目前还没有应用申请。`AGENT.md`、技能和触发器([ADR 0002(英文)](docs/adr/0002-event-driven-app-agents.md))尚未实现:应用 Agent 只在系统 Agent、用户或卡片请求时运行。 **从系统 Agent 到 glance 屏幕上的一张卡片**: @@ -275,7 +279,7 @@ Shell 只有一份,位于 `crates/shell`([ADR 0001(英文)](docs/adr/000 每个 Shell 运行一个 [octos](https://github.com/octos-org/octos) Agent 内核,首次使用时启动:Android 上是 APK 中的 `liboctos.so`,OpenHarmony 上在进程内运行,桌面端运行 `OCTOS_APP_CORE_BIN` 指定的二进制,iOS 上没有。用户在系统应用 **AI providers** 中、在宿主面板上选择模型并输入密钥;密钥保存在平台的密钥存储中,永远不会到达应用。[`crates/ai-host`](crates/ai-host/README.md) 是两个 Shell 的统一入口,[`crates/app-peers`](crates/app-peers/README.md) 为每个获授权的原生应用分配自己的 octos peer(私有的上下文、工作区和记忆 `app//acct-`),归 Shell 的系统 Agent 所有。peer 的工具审批只能由用户在该应用中回答,系统 Agent 无法代答。 -目前可用的:原生模块(Rinx)使用自己的 peer;AppCard(需主动开启)直接使用内核。隔离运行的脚本应用,无论系统应用还是商店应用,在托管了内核的 Shell 中通过 `octos` 宿主服务使用助手:每个应用有自己的、由宿主拥有的 peer(`card.<应用 id>`),它的工具审批和其他应用 Agent 一样交给 Shell 的审批面板([#155](https://github.com/OctoSense-org/OctoSense/pull/155))。`llm` 服务只为 `os.*` 应用管理提供方。应用自己的 Agent(`tools.json`、`AGENT.md`、skills、触发器、glance 卡片)见 [ADR 0002](docs/adr/0002-event-driven-app-agents.md);自 [#160](https://github.com/OctoSense-org/OctoSense/pull/160) 起,应用 `tools.json` 中的工具已端到端提供给它的 Agent。 +目前可用的:原生模块(Rinx)使用自己的 peer;AppCard(需主动开启)直接使用内核。隔离运行的脚本应用,无论系统应用还是商店应用,在托管了内核的 Shell 中通过 `octos` 宿主服务使用助手:每个应用有自己的、由宿主拥有的 peer(`card.<应用 id>`),它的工具审批和其他应用 Agent 一样交给 Shell 的审批面板([#155](https://github.com/OctoSense-org/OctoSense/pull/155))。`llm` 服务只为 `os.*` 应用管理提供方。应用自己的 Agent(`tools.json`、`AGENT.md`、skills、触发器、glance 卡片)见 [ADR 0002](docs/adr/0002-event-driven-app-agents.md);自 [#160](https://github.com/OctoSense-org/OctoSense/pull/160) 起,应用 `tools.json` 中由宿主服务实现的工具已通过 Shell relay 提供给其 Agent。标为 `implemented_by: "app"` 的工具仍缺少 Card runner 执行器;声明不等于实现。 架构、信任模型、各类应用能用什么、规划及其状态,以及如何在本地运行和测试:[docs/ai-services.zh-CN.md](docs/ai-services.zh-CN.md)。它在整个系统中的位置:[docs/architecture.zh-CN.md](docs/architecture.zh-CN.md)。面向应用开发者:OctoScript-App-Design-Flow 的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md)。 diff --git a/apps/AGENTS.md b/apps/AGENTS.md index f4a78eda..9d301216 100644 --- a/apps/AGENTS.md +++ b/apps/AGENTS.md @@ -80,7 +80,9 @@ app's own agent and `tools.json`, the system toolbox, `glance.publish` and ## AppCard (apps/appcard) -AppCard is the one native app: Rust crates, not a bundle. Its own rules +AppCard is an opt-in native assistant: Rust crates, not a bundle. Reference +(`apps/reference`) is another native app; other native apps are linked from +external crates through `native-apps.json`. Its own rules are in [appcard/AGENTS.md](appcard/AGENTS.md); in short: - Its crates (`apps/appcard/app/app`, `apps/appcard/app/crates/*`, @@ -105,3 +107,20 @@ are in [appcard/AGENTS.md](appcard/AGENTS.md); in short: dependency. - CI for it is the `apps` job of `.github/workflows/apps.yml`, which runs on changes under `apps/`, `crates/` and the workspace files. + +## Architecture review and data access + +Use the [product walkthrough](../desktop/docs/code-walkthrough.md) and +[agent walkthrough](../docs/architecture-walkthrough.md) when changing docs. +Keep host-service API methods, declared agent tools and agent-workspace files +separate. Mail currently declares only `mail.notify` in `bundle/tools.json`; +its UI service methods do not automatically become tools. Calendar's script +window is an instruction screen; the agent calls its Rust service for events. +News fetch timers do not currently trigger LLM turns. State these limits rather +than documenting intended behavior as shipped. + +App Hub's Card runner and the optional AppCard assistant are different modules. +AppCard's historical personal-data mailbox reader is not the current Mail store. +Keep English/Chinese README changes paired and mark unrun launch/device recipes +as unverified. Documentation-only changes need link/source checks, not new +implementation-mirroring tests. diff --git a/apps/README.md b/apps/README.md index 73dd4540..8d0ba0a7 100644 --- a/apps/README.md +++ b/apps/README.md @@ -2,6 +2,8 @@ English | [简体中文](README.zh-CN.md) +**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, real app data and Android platform boundaries; it marks unrun recipes explicitly. + > **Where this fits.** The system apps are script apps in App Hub's Card runner. They never talk to the octos kernel. News, Mail and Calendar have an agent (one host-owned octos peer per app and account, `card.`), declared by their manifest's `agent` block and `tools.json`; the shell drives it for the system agent, the shell's "Ask " panel and a card's in-card chat, and an app could also reach it with `host.request("octos.*")` (none of them does). The agent's calls to the app's tools come back through the shell's relay and approval router and run on the app's host service; Mail's and Calendar's tools put cards on the glance screen ([App agents](#app-agents)). An app's glance cards run under the app's own policy, and what the person does on them is the app's own action, not an agent tool call. Diagrams of the processes, an app agent's two lanes and a tool call with its approval: [How it fits together](../README.md#how-it-fits-together); the details: [docs/architecture.md](../docs/architecture.md) and [ADR 0004](../docs/adr/0004-native-apps-hosting-and-peers.md). The first-party apps that ship with [OctoSense](https://github.com/OctoSense-org), @@ -365,6 +367,14 @@ model lane and tools. Which system apps have one, and how | Mail | `agent` block, `glance`, `storage.accounts` (the agent acts for the signed-in account) | `mail.notify` (act, background) | `notice.card` | | Calendar | `agent` block, `glance` | `calendar.events` (read), `calendar.add_event` (act), `calendar.remove_event` (destructive, `confirm: host`), `calendar.notify`, `calendar.agenda` (act) | `event.card`, `agenda.card` | +**A service API is not automatically an agent tool.** Mail currently exposes +only `mail.notify` in its agent tool file; its UI's `mail.list`, `mail.message` +and `mail.send` methods are not thereby available to its agent. The peer's +workspace also does not mount Mail's host database or credential vault. Calendar +is a working example of an agent reading/writing its app data through declared +Rust tools; its script window currently only explains how to ask the agent. +See the [data-access walkthrough](../desktop/docs/code-walkthrough.md#4-follow-real-data-through-a-tool-not-through-the-model). + - **Declaring one.** The manifest's `agent` block names the kernel tools the agent may use (`"tools": ["ask_user_question"]`; a dotted name there asks for another app's shareable tool), and `bundle/tools.json` declares the diff --git a/apps/README.zh-CN.md b/apps/README.zh-CN.md index 1adca50d..5bbd5593 100644 --- a/apps/README.zh-CN.md +++ b/apps/README.zh-CN.md @@ -2,6 +2,8 @@ [English](README.md) | 简体中文 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、真实数据和 Android 平台边界,并明确标注未运行的配方。 + > **在整个系统中的位置。**系统应用是运行在 App Hub 的 Card runner 中的脚本应用。它们从不直接与 octos 内核通信。新闻、邮件和日历有 Agent(每个应用、每个账号一个由宿主拥有的 octos peer,`card.<应用 id>`),由 manifest 的 `agent` 块和 `tools.json` 声明;Shell 替系统 Agent、Shell 的 “Ask ” 面板和卡片的卡内对话驱动它,应用自己也可以用 `host.request("octos.*")` 使用它(目前没有应用这样做)。Agent 对应用工具的调用经由 Shell 的中转和审批路由回到应用,在应用的宿主服务上运行;邮件和日历的工具会把卡片放到 glance 屏幕上([应用 Agent](#应用-agent))。应用的 glance 卡片在应用自己的策略下运行,用户在卡片上的操作是应用自己的操作,而不是 Agent 的工具调用。进程、应用 Agent 的两条通道以及一次带审批的工具调用的图示:[整体如何运作](../README.zh-CN.md#整体如何运作);详细说明:[docs/architecture.zh-CN.md](../docs/architecture.zh-CN.md) 和 [ADR 0004(英文)](../docs/adr/0004-native-apps-hosting-and-peers.md)。 [OctoSense](https://github.com/OctoSense-org/.github/blob/main/profile/README.zh-CN.md)(运行在操作系统之上的 Agent 交互 Shell)自带的第一方应用,以及它们背后的宿主服务。 @@ -324,6 +326,12 @@ Shell 把日历 Agent 的 `calendar.*` 工具当作这个系统应用自己的 | 邮件 | `agent` 块、`glance`、`storage.accounts`(Agent 代表已登录的账户工作) | `mail.notify`(act,后台) | `notice.card` | | 日历 | `agent` 块、`glance` | `calendar.events`(read)、`calendar.add_event`(act)、`calendar.remove_event`(destructive,`confirm: host`)、`calendar.notify`、`calendar.agenda`(act) | `event.card`、`agenda.card` | +**宿主服务 API 不会自动成为 Agent 工具。** Mail 的 Agent 工具文件目前仅暴露 +`mail.notify`;UI 使用的 `mail.list`、`mail.message` 和 `mail.send` 不会因此对 +Agent 开放。Peer 的工作目录也不会挂载 Mail 的宿主数据库或凭据保险库。Calendar +展示了通过显式声明的 Rust 工具读写应用数据的路径;它的脚本窗口目前只是 Agent +使用说明。见[数据访问源码导读](../desktop/docs/code-walkthrough.zh-CN.md)。 + - **声明。** manifest 的 `agent` 块列出 Agent 可以使用的内核工具(`"tools": ["ask_user_question"]`; 其中带点的名称表示申请另一个应用的可共享工具),`bundle/tools.json` 声明应用自己的工具: `.`、`input_schema`、`output_schema`、`risk`(`read`、`act`、`destructive`)、 diff --git a/apps/appcard/AGENTS.md b/apps/appcard/AGENTS.md index 0a7f4c66..7dee83e1 100644 --- a/apps/appcard/AGENTS.md +++ b/apps/appcard/AGENTS.md @@ -50,3 +50,11 @@ All paths below are relative to `apps/appcard/` unless they say otherwise. force-push `main`. - Follow the Makepad `script_mod!` DSL conventions of the `.sources/makepad` checkout (`Name: value`, `name := Type{}`, `+:` merge). + +## Current shell architecture + +AppCard is opt-in (`app-appcard`) and separate from App Hub's `CARD_MODULE`, +the current system chat and the app-peer broker. Keep its router/composer and +legacy personal-data docs scoped to this app. Reference is also a native app; +do not describe AppCard as the repository's only native app. See the +[product walkthrough](../../desktop/docs/code-walkthrough.md). diff --git a/apps/appcard/README.md b/apps/appcard/README.md index c45f6309..01b6f1b2 100644 --- a/apps/appcard/README.md +++ b/apps/appcard/README.md @@ -9,9 +9,15 @@ or composes an app agent, and that agent generates a live interactive card. The card is a Splash DSL card or a webview card, and it binds real data at render time. -Unlike the other apps in `apps/`, AppCard is not (yet) a contained -script app with a `bundle/`. It is the one **native** app here: a Rust module -(`octos-app`) that the shells link in-process. +AppCard is an optional **native** Rust app, not a contained script bundle. +The shells link it in-process through `octosense-appcard`; Reference is another +native app in this repository. Enable `app-appcard` explicitly: default builds +and `mobile-apps` do not include it. + +The shared shell's system chat and app-agent broker work without AppCard. Its +router/composer and older personal-data integration are a separate product path, +not the implementation of every script app's peer or current Mail storage. See +the [source walkthrough](../../desktop/docs/code-walkthrough.md). What lives here (paths relative to `apps/appcard/`): diff --git a/apps/appcard/README.zh-CN.md b/apps/appcard/README.zh-CN.md index a27d097d..e94d2ad2 100644 --- a/apps/appcard/README.zh-CN.md +++ b/apps/appcard/README.zh-CN.md @@ -7,8 +7,13 @@ 路由大脑(AMA)选择或组合一个应用 Agent,由该 Agent 生成一张实时的交互卡片。 卡片是 Splash DSL 卡片或 webview 卡片,在渲染时绑定真实数据。 -与 `apps/` 中的其他应用不同,AppCard(目前)还不是带 `bundle/` 的隔离运行脚本应用。 -它是这里唯一的**原生**应用:一个由 Shell 进程内链接的 Rust 模块(`octos-app`)。 +AppCard 是可选的**原生** Rust 应用,不是隔离脚本 bundle。Shell 通过 +`octosense-appcard` 在进程内链接它;Reference 是本仓库另一个原生应用。 +必须显式开启 `app-appcard`;默认构建和 `mobile-apps` 都不包含它。 + +共用 Shell 的系统聊天和应用 Agent broker 无需 AppCard 即可工作。它的 +router/composer 和较早的 personal-data 集成是一条独立产品路径,不是所有 +脚本应用 Peer 或当前 Mail 存储的实现。见[源码导读](../../desktop/docs/code-walkthrough.zh-CN.md)。 目录内容(路径相对于 `apps/appcard/`): diff --git a/crates/kernel/README.md b/crates/kernel/README.md index 27188fc0..00c18a75 100644 --- a/crates/kernel/README.md +++ b/crates/kernel/README.md @@ -90,9 +90,9 @@ cursors, so the app carries on. **Other consumers.** Each takes its own connection (`connect()`) and gets only its sessions' traffic: the system chat opens `_main:api:octosense#system`; an app-peers broker drives its app's peer and request contexts (Rinx's mini -apps are request contexts of Rinx's peer, through `OctosAppService`, not -sessions of their own). Each must handle `CloseReason::Restarted` by -reconnecting. +apps use request contexts of Rinx's peer through `OctosAppService`; each +context has its own kernel session/transcript, but is not another app peer). +Each must handle `CloseReason::Restarted` by reconnecting. Other functions: `core_dir()`, `home()`, `profile()`, `launch()` / `is_available()` (whether and how a kernel would start), `status()`, and the diff --git a/crates/kernel/README.zh-CN.md b/crates/kernel/README.zh-CN.md index cea963c0..376f0c9a 100644 --- a/crates/kernel/README.zh-CN.md +++ b/crates/kernel/README.zh-CN.md @@ -81,7 +81,7 @@ AppCard 的传输层(`apps/appcard/app/crates/octos-app-transport`,`kernel.r **其他使用方。** 每个使用方都用自己的连接(`connect()`),只收到自己会话的流量:系统对话 打开 `_main:api:octosense#system`;app-peers 代理驱动其应用的 peer 和请求上下文(Rinx 的 -小程序是 Rinx 的 peer 的请求上下文,经 `OctosAppService` 使用,没有自己的会话)。每个使用方 +小程序经 `OctosAppService` 使用 Rinx peer 的请求上下文;每个上下文有自己的内核会话和记录,但不是另一个应用 peer)。每个使用方 都必须通过重新连接来处理 `CloseReason::Restarted`。 其他函数:`core_dir()`、`home()`、`profile()`、`launch()` / `is_available()`(是否以及如何 @@ -192,3 +192,5 @@ CI:`.github/workflows/apps.yml`(`services` 任务测试本 crate;`apps` 链接 `octos-cli`,二者都使用根目录 `Cargo.toml` 为所有 octos crate 锁定的同一个 rev。为 OpenHarmony 构建它的工作区还需要 `nix` 补丁(octos rev `18fcd3f1`,见根目录 `Cargo.toml` 的 `[patch.crates-io]`)。其他平台上,内核是用同一 rev 构建的独立二进制文件。 + +源码阅读补充:Rinx mini app 的 request context 有自己的内核会话和记录,但不是另一个应用 peer。线程、runtime 与回合任务的对应关系见[代码导读](../../docs/architecture-walkthrough.zh-CN.md#10-映射到-rust线程和-tokio)。 diff --git a/desktop/AGENTS.md b/desktop/AGENTS.md new file mode 100644 index 00000000..8b099107 --- /dev/null +++ b/desktop/AGENTS.md @@ -0,0 +1,18 @@ +# Working on the desktop product + +The [repository rules](../AGENTS.md) apply. Read the +[product source walkthrough](docs/code-walkthrough.md) before changing startup +or documenting native/script app hosting. + +- `src/main.rs` is the entry point; shared UI and hosting belong in + `../crates/shell/`, not copies under this directory. +- Run desktop Cargo commands from the root or this directory. Home commands + must run from `../phone/` to pick up its Cargo environment. +- `--module` selects native hosting; startup launch can be requested with + `MAKEPAD_WM_TEST_APP`. Match Cargo features to `../native-apps.json`. +- App Hub's Card runner is not the optional AppCard assistant. A native module, + a child process, an app-agent peer and a Tokio task are different concepts. +- For code changes, use the desktop and shared-shell checks named in the root + instructions. For documentation changes, inspect referenced symbols and + relative links; mark commands not executed as unverified. Change both README + languages together. Use hidden windows for UI validation. diff --git a/desktop/README.md b/desktop/README.md index a9a79019..2896cc73 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -2,6 +2,8 @@ English | [简体中文](README.zh-CN.md) +**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, real app data and Android platform boundaries; it marks unrun recipes explicitly. + > **Where this fits.** The desktop is one shell process with the octos kernel as its child (`OCTOS_APP_CORE_BIN`). App Hub, the Card runner with the script apps, and Rinx run in process; the Terminal runs as its own process, in an OS sandbox on macOS and Linux (not yet on Windows), attached over the shell's hub. On macOS that sandbox keeps `~/.cargo`, `~/.rustup` and the OctoSense checkout read-only, so run `cargo install`, `rustup update` and builds of OctoSense itself in another terminal. Diagrams of the processes, an app agent's two lanes and a tool call with its approval: [How it fits together](../README.md#how-it-fits-together); the details: [docs/architecture.md](../docs/architecture.md) and [ADR 0004](../docs/adr/0004-native-apps-hosting-and-peers.md). The desktop shell of [OctoSense](https://github.com/OctoSense-org), the agent shell on top of your operating system, and the desktop packaging of the OctoSense repository (formerly the OctoSense-Desktop repository). It is one Makepad window that is the desktop: a launcher, a dock and tiles, hosting system apps and App Hub store apps as contained script programs, trusted native modules in-process, and Makepad developer programs as child processes. It gets its apps the same way the phone shell, [Home](../phone/README.md), does. Setup, the repository layout and CI are in the [root README](../README.md). @@ -81,7 +83,7 @@ The native apps' features (`app-hub`, `app-rinx`, `app-reference`, `app-sheets`, | Feature | Default | Effect | | --- | --- | --- | -| `app-hub` | on | Links `octosense-app-hub-app` (store `apphub`, Card runner `card`, system apps) and the host services `octosense-mail-service` (Mail) and `octosense-llm-service` (AI providers). Without it the build has no App Hub and no system apps. | +| `app-hub` | on | Links `octosense-app-hub-app` (store `apphub`, Card runner `card`, system apps) and the Mail, News, Calendar and AI providers host services. Without it the build has no App Hub and no system apps. | | `octos-core` | on | The octos kernel service (`octosense-kernel`, from `../crates/kernel`) and the app-agent broker (`octosense-app-peers`): the one kernel AppCard, Rinx and other consumers share, configured by AI providers. Always on for Android and iOS. Leave it out with `--no-default-features --features app-hub` (and whatever else you want). | | `app-rinx` | on | Links [Rinx](https://github.com/hagency-org/Rinx), the Matrix client, as a module; implies `octos-core` (its assistant is the shell's). | | `app-reference` | off | Links Reference (`../apps/reference`) as a module. | diff --git a/desktop/README.zh-CN.md b/desktop/README.zh-CN.md index 34bf5635..3a446e4f 100644 --- a/desktop/README.zh-CN.md +++ b/desktop/README.zh-CN.md @@ -2,6 +2,8 @@ [English](README.md) | 简体中文 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、真实数据和 Android 平台边界,并明确标注未运行的配方。 + [OctoSense](https://github.com/OctoSense-org)(运行在操作系统之上的 Agent 交互 Shell)的桌面端 Shell,也是 OctoSense 仓库中的桌面端打包(原为 OctoSense-Desktop 仓库)。它是一个 Makepad 窗口,这个窗口本身就是桌面:launcher、dock 和平铺窗格(tile)。系统应用和 App Hub 商店应用以隔离的脚本程序运行,受信任的原生模块在进程内运行,Makepad 开发者程序作为子进程运行。它获取应用的方式与手机 Shell [Home](../phone/README.zh-CN.md) 完全相同。环境准备、仓库结构和 CI 见[根目录 README](../README.zh-CN.md)。 > **在整个系统中的位置。**桌面端是一个 Shell 进程,octos 内核是它的子进程(`OCTOS_APP_CORE_BIN`)。App Hub、运行脚本应用的 Card runner 和 Rinx 在进程内运行;Terminal 作为独立进程运行,在 macOS 和 Linux 上运行在系统沙箱中(Windows 上尚未实现),通过 Shell 的 hub 连接。在 macOS 上,该沙箱中 `~/.cargo`、`~/.rustup` 和 OctoSense 源码目录是只读的,因此 `cargo install`、`rustup update` 以及构建 OctoSense 本身都要在其他终端里运行。进程、应用 Agent 的两条通道以及一次带审批的工具调用的图示:[整体如何运作](../README.zh-CN.md#整体如何运作);详细说明:[docs/architecture.zh-CN.md](../docs/architecture.zh-CN.md) 和 [ADR 0004(英文)](../docs/adr/0004-native-apps-hosting-and-peers.md)。 @@ -81,7 +83,7 @@ cargo run --release -p octosense | Feature | 默认 | 作用 | | --- | --- | --- | -| `app-hub` | 开 | 链接 `octosense-app-hub-app`(商店 `apphub`、Card 运行器 `card`、系统应用)以及宿主服务 `octosense-mail-service`(邮件)和 `octosense-llm-service`(AI 提供商)。没有它,构建中既没有 App Hub 也没有系统应用。 | +| `app-hub` | 开 | 链接 `octosense-app-hub-app`(商店 `apphub`、Card 运行器 `card`、系统应用)以及 Mail、News、Calendar 和 AI providers 宿主服务。没有它,构建中既没有 App Hub 也没有系统应用。 | | `octos-core` | 开 | octos 内核服务(`octosense-kernel`,来自 `../crates/kernel`)和应用与 Agent 之间的代理(`octosense-app-peers`):AppCard、Rinx 等使用方共享的唯一内核,由 AI 提供商配置。Android 和 iOS 上始终开启。用 `--no-default-features --features app-hub`(再加上需要的其他 feature)可以去掉它。 | | `app-rinx` | 开 | 以模块形式链接 Matrix 客户端 [Rinx](https://github.com/hagency-org/Rinx);隐含 `octos-core`(它的助手就是 Shell 的助手)。 | | `app-reference` | 关 | 以模块形式链接 Reference(`../apps/reference`)。 | diff --git a/desktop/docs/code-walkthrough.md b/desktop/docs/code-walkthrough.md new file mode 100644 index 00000000..d72bebc8 --- /dev/null +++ b/desktop/docs/code-walkthrough.md @@ -0,0 +1,281 @@ +# Walking through the desktop, Home, ROM and system apps + +English | [简体中文](code-walkthrough.zh-CN.md) + +This is a source-reading tutorial for a Rust developer who is new to OctoSense. +Paths below are relative to the repository root. The companion +[agent architecture walkthrough](../../docs/architecture-walkthrough.md) follows +the kernel, peers, tools and Tokio tasks in more detail. + +The launch recipes below are **unverified in this documentation review**: their +package names, features and entry points were checked against source, but no GUI, +Android APK, ROM image or device was launched. Existing dated validation records +remain separate evidence. Run setup as described in the root README before using +Cargo; reuse existing framework clones with the sources-hub configuration. + +## 1. Start with the nouns + +| Name | What actually runs | +| --- | --- | +| Desktop | The `octosense` executable; a thin entry point for `octosense-shell`. | +| Home | The `octosense-home` executable/APK; the same shell plus built-in Settings and platform integration. | +| Native app | Rust implementing Makepad's `AppModule`, or a separate executable hosted through the window-manager protocol. | +| OctoScript app | An admitted `manifest.json` + `main.splash` bundle, interpreted inside App Hub's Card runner. | +| Host service | Rust code that performs a specific operation for an attributed app and returns data. It need not use a model. | +| App agent | A model-driven octos peer scoped to an app/account, with a workspace, sessions and explicitly granted tools. | +| System agent | The shell's assistant, with its own tool policy and delegation tools. | +| ROM privileged agent | An Android Java/Binder service for platform operations. It is a different component from the model-driven system agent. | + +A Rust `trait` describes an interface; `impl AppModule` supplies one implementation. +A `Widget` handles UI events and drawing. Neither implies a thread, an LLM nor a +Tokio task. Likewise, a Splash file can be a native widget description or a +contained app's program: the host and its policy determine the authority. +Here `main.splash` runs on Makepad Script/Splash. The separate Octoscript L0 +parser/checker and `.card` lowering path are not the parser for that program. +“OctoScript app” is the product name used by these guides, not a claim that +these two language implementations are identical. + +## 2. Run the smallest native example + +From the repository root, after setup: + +```sh +# An ordinary standalone Reference window. +cargo run --locked -p octosense-reference + +# Reference linked into the desktop and opened as a module. +MAKEPAD_WM_TEST_APP=reference cargo run --locked -p octosense --features app-reference -- --module reference + +# The normal desktop product (App Hub, Rinx, Terminal, kernel integration). +cargo run --locked --release -p octosense +``` + +These are development recipes, **unverified here**. To inspect UI without taking +over the screen, add `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=8000` and use the +Makepad control endpoints documented by `/help`; end the run through `/quit`. +`--module` selects hosting; `MAKEPAD_WM_TEST_APP` requests startup launch. + +Read these files in order: + +1. [`apps/reference/src/lib.rs`](../../apps/reference/src/lib.rs): + `ReferenceView` holds `count: usize`; `handle_event` receives button/text + actions and changes labels. `draw_walk` delegates drawing to the contained + `View`. This is ordinary UI state, with no agent involved. +2. The same file's `ReferenceModule`: `register` makes its widget type known to + the VM; `create` returns `InstanceParts` containing a root widget, a service + executor and shutdown callback. The executor says “Reference has no tools”. + A native app does not automatically acquire an agent. +3. [`native-apps.json`](../../native-apps.json): Reference's source, feature, + hosting, storage and empty agent grants. This manifest generates the native + app registry and Cargo feature blocks; do not edit the generated blocks. +4. [`desktop/src/main.rs`](../src/main.rs): imports the shell's `App` and calls + `octosense_main!`. In [`crates/shell/src/lib.rs`](../../crates/shell/src/lib.rs), + that macro delegates to Makepad's `app_main!` and selects the package directory. +5. Follow `App::launch_app_with_args` in that shell file. It finds a registered + app, checks script-app identity/admission where applicable, prepares storage, + optionally focuses an existing window, then chooses module or process hosting. +6. [`crates/shell/src/module_host.rs`](../../crates/shell/src/module_host.rs), + `ModuleHost::create`: establishes an instance scope, storage namespace, reply + handles, viewport and VM, then builds the module. Agent services are injected + only when declared and granted by host policy. + +For process hosting, continue to +[`crates/shell/src/clients.rs`](../../crates/shell/src/clients.rs) and +[`crates/process-apps`](../../crates/process-apps). The shell starts a child, +connects the window-manager protocol, forwards input and displays its surface. +That child process is independent of any octos peer. Terminal normally uses this +path on macOS/Windows and with Vulkan in a Linux Wayland session; its module +fallback and overrides are described in the [desktop README](../README.md). + +## 3. Run and follow a script bundle + +The normal desktop already contains the selected system bundles. Open News or +Calendar from the launcher. A standalone preview uses the App Hub repository's +`card-host`; from an App Hub checkout after its own setup: + +```sh +# Replace the example path with your OctoSense checkout. +cargo run --locked --release -p octosense-card-host --bin card-host -- --bundle /path/to/OctoSense/apps/news/bundle --system +``` + +This recipe is **unverified here**. `--system` admits the shipped `os.*` bundle; +it does not give the preview the shell's host services or agent UI. In particular, +Mail requires the shell's service. A source-backed desktop recipe is: + +```sh +MAKEPAD_APP_CONFIG='{"mail_demo":true}' cargo run --locked --release -p octosense +``` + +The demo account uses password `demo`; its sends stay in the demo. New store apps +belong in OctoScript-App-Design-Flow, then App Hub's admission/publishing flow. +Use a local catalog to test the real shell installation path; see +[the desktop local-catalog recipe](../README.md#try-your-own-app-before-it-is-published). + +Read [`desktop/system-apps.json`](../system-apps.json) and +[`phone/system-apps.json`](../../phone/system-apps.json): these select bundles +from `apps/`. Follow [`crates/shell/src/apps.rs`](../../crates/shell/src/apps.rs) +for launcher entries, `agent_apps` and `register_host_services`. The linked App +Hub `CARD_MODULE` is a native host for those interpreted programs. It is distinct +from the opt-in AppCard assistant module. + +An app's manifest requests capabilities; admission converts those requests into +a policy. A script's `host.request(...)` is checked under that app's identity. +It is not arbitrary Rust execution and not automatically an LLM tool call. +App Hub's `crates/appstore/src/services.rs` defines `HostService`, `ServiceCall` +and replies. `ServiceCall` carries the app identity and host directory; a service +can check both the method and caller before doing work. + +## 4. Follow real data through a tool, not through the model + +Start with [`apps/calendar/bundle/tools.json`](../../apps/calendar/bundle/tools.json) +and [`apps/calendar/host-service/src/lib.rs`](../../apps/calendar/host-service/src/lib.rs). +The JSON declares tools and schemas; it contains no implementation. The Rust +`CalendarService` implements the host-service interface; `handle` dispatches +methods, while `load`/`save` own `/calendar/events.json`. + +For “add an event”, the path is: + +```mermaid +sequenceDiagram + participant H as Human or system agent + participant A as Calendar app agent + participant R as Shell tool relay + participant C as Calendar Rust service + participant D as events.json + H->>A: Ask Calendar to add an event + A->>R: calendar.add_event + structured arguments + R->>R: Check caller, grant, schema and policy + R->>C: Execute as os.calendar + C->>D: Load, validate and save + C-->>R: Object result (event id/start) + R-->>A: Tool result + A-->>H: Answer in the requesting conversation +``` + +Read [`crates/shell/src/host_tools/script_apps.rs`](../../crates/shell/src/host_tools/script_apps.rs) +for tool loading and `HostServiceExecutor`, then `host_tools/relay.rs` for +authorization. `calendar.remove_event` is destructive and needs the configured +host confirmation. `calendar.notify`/`agenda` fill fixed `.card` resources and +call the publisher installed by `register_host_services`; the shell checks the +app's `glance` grant. The model supplies arguments, not executable card code. + +Do not confuse these three stores/interfaces: + +| Boundary | Actual access | +| --- | --- | +| Script storage | The app's storage capability and jail; only the runtime's allowed APIs. | +| Agent workspace | The peer's app/account directory; only explicitly granted file tools, confined by shell policy. It is not a mount of every host-service database. | +| Host-service database | Rust-owned data such as Calendar events, Mail cache and credentials, or News cache; accessed through explicitly exposed methods/tools. Secrets stay with host-owned sheets and vaults. | + +Current examples deliberately differ. News declares `news.list` and `news.read`. +Mail's **agent tool file declares only `mail.notify`**: the service's UI methods +`mail.list`, `mail.message` and `mail.send` are not thereby agent tools. Calendar's +window currently explains how to ask its agent; it does not list/edit events +through a script `calendar` capability, which App Hub does not expose. + +Cross-app access also needs explicit declarations: the requesting agent asks for +a dotted tool name in `agent.tools`; the owner must offer a shareable tool, and +the relay must grant and execute it under the right identities. App Hub admission +also checks `HostLimits.offered_tools`; arbitrary dotted names such as +`mail.send` are not offered by default, so editing `agent.tools` alone does +not make the bundle admissible. A writable +workspace or a chat message does not grant another app's files, credentials or +API. See the companion walkthrough for system-agent delegation and current +limits on reverse requests from an app agent to the system agent. + +## 5. Where a person talks to the app agent + +The shell draws an **Ask <app>** panel for agent-enabled apps. On desktop, +focus the app and use the bar, Shift+F8, or “Ask this app's agent” in the menu. +First-use consent precedes preparation of its peer. F8 opens the system agent; +`agents.ask` requests consent/preparation, then `peer_send_input` delegates work +and `peer_gather` retrieves the answer. A card's `sys.chat` can also address its app +agent. Phone touch navigation has no equivalent panel-opening control yet. + +Follow `crates/shell/src/app_chat/`, `crates/shell/src/system_chat/`, +`crates/shell/src/agents.rs`, `crates/ai-host/src/contained.rs` and +`crates/app-peers/`. The human conversation and system-agent conversation have +separate lanes/sessions on the app's peer; the panel's Stop interrupts the +human's turn. “One peer” does not mean “one shared transcript”, “one OS thread” +or “one Tokio task”. The Makepad event loop handles UI; broker/kernel work and +notifications cross their own channels. The companion walkthrough maps those +channels and kernel tasks to source symbols. + +The kernel must also be configured: `octos-core` links the integration but does +not manufacture a desktop `octos` executable or a provider credential. Supply a +compatible `OCTOS_APP_CORE_BIN`, configure AI providers and use the +[kernel guide](../../crates/kernel/README.md). Android packages bundle +`liboctos.so`; desktop and Android normally run a child kernel, while +OpenHarmony uses the in-process core. These are kernel hosting choices, separate +from whether the app UI is a module or child process. + +## 6. Home adds Settings around the shared shell + +Run Cargo **from `phone/`**, because its `.cargo/config.toml` selects the phone's +bundles. From that directory, the desktop preview recipe (**unverified here**) is: + +```sh +cargo run --locked --release -p octosense-home --features mobile-only +# Add Reference/Sheets too; mobile-only and mobile-apps have different jobs. +cargo run --locked --release -p octosense-home --features mobile-only,mobile-apps +``` + +[`phone/src/main.rs`](../../phone/src/main.rs) defines `App` with `#[deref] +shell: ShellApp` plus `SettingsRuntime`. Dereferencing lets its implementation +reach shell fields; it does not create another shell process. `install_ext` +registers the trusted Settings module. In `handle_event`, Home first handles +Settings startup/timing and entry intents, lets the shell process the event, +then consumes queued platform packets and Settings requests. Observe that +ordering when debugging a missing Settings update. + +Follow `phone/src/settings_app.rs`, `settings_script.rs` and +`settings_script_host_facade.rs`: Settings combines a script-owned controller/UI +with Rust host checks. Its privilege comes from the compiled trusted singleton, +not from a script declaring itself “settings”. `android_settings.rs` dispatches +observations/results by channel. A returned command result and a later observed +platform state are distinct; accepted work must not be displayed as confirmed +platform state prematurely. + +On Android, continue into +`phone/resources/android/java/dev/makepad/octosense/MakepadAppExtension.java`, +the clients there, and `phone/android/contracts/`. The System Bridge's +`SystemBridgeService.java` uses Binder callbacks and caller checks. Ordinary +standalone Home has only available Android permissions/roles; installing Home +does not give it ROM privileges. Follow [Home's build instructions](../../phone/README.md#build-and-run) +for APK packaging; a desktop preview proves neither Binder nor device behavior. + +## 7. The ROM packages the platform, not another LLM peer + +Read [`rom/vendor/octosense/octosense.mk`](../../rom/vendor/octosense/octosense.mk) +and `Android.bp` for product inclusion, then +[`rom/scripts/build-home.py`](../../rom/scripts/build-home.py), `stage-home.py` +and `stage-forks.sh`. Build produces the Home/Bridge APK pair and receipt; +staging verifies and copies artifacts; the LineageOS build produces the image. +Installing, flashing and OTA delivery are separate operations. + +The privileged Android service lives in +`rom/vendor/octosense/agent/src/dev/makepad/octosense/agent/AgentPlatformService.java`. +Its `caller` checks Binder UID, allowed package identity and platform signature; +methods use platform backends and report capabilities/results. Its AIDL contract +is `IAgentPlatform.aidl`. It is a Java service with Android lifecycle and Binder +execution, not an octos model loop and not a Rust Tokio app-agent task. + +Home's `AgentPlatformClient` connects to that optional ROM service. The System +Bridge, Quickstep, SystemUI, Settings brokers and privileged agent are distinct +Android pieces, not a universal “system agent” API an arbitrary app can call. +Source checks cannot prove that a ROM boots or that its platform integration +works; image/device validation remains **unverified in this review**. + +## 8. Keep the older AppCard path separate + +`apps/appcard/module/src/lib.rs` adapts the optional AppCard assistant to +`AppModule`; `apps/appcard/app/app` implements its router/composer and generated +cards, with transport/store/render crates beside it. Enable it explicitly with +`--features app-appcard`; defaults and `mobile-apps` leave it out. + +AppCard's older routing/composition terminology is not the implementation of +every modern system/app agent. The current system chat, app-chat broker and +contained script agents work without enabling AppCard. Likewise its legacy +`personal-data` mailbox reader is not current Mail's host-service database API. +For learning native hosting, start with Reference; for shipped app-agent tools, +start with Calendar/News; read AppCard when working on that optional product. diff --git a/desktop/docs/code-walkthrough.zh-CN.md b/desktop/docs/code-walkthrough.zh-CN.md new file mode 100644 index 00000000..0bd0be22 --- /dev/null +++ b/desktop/docs/code-walkthrough.zh-CN.md @@ -0,0 +1,147 @@ +# 桌面、Home、ROM 与系统应用源码导读 + +[English](code-walkthrough.md) | 简体中文 + +本文面向刚接触 OctoSense 的 Rust 开发者。文中的源码路径相对于仓库根目录。 +[Agent 架构导读](../../docs/architecture-walkthrough.zh-CN.md)进一步追踪内核、Peer、工具和 Tokio 任务。 + +以下启动配方均为**本次文档审查未验证**:已核对源码中的包名、feature 和入口,但没有启动 GUI、构建 Android APK/ROM 或运行设备测试。已有的带日期验证记录是独立证据。运行 Cargo 前按根目录 README 准备依赖;已有框架克隆时通过 sources hub 复用。 + +## 1. 先理解几个名称 + +| 名称 | 实际运行的东西 | +| --- | --- | +| 桌面 | `octosense` 可执行程序,入口很薄,主体是 `octosense-shell`。 | +| Home | `octosense-home` 程序/APK,共用 Shell,加上内置设置和平台集成。 | +| 原生应用 | 实现 Makepad `AppModule` 的 Rust 模块,或通过窗口管理协议托管的独立程序。 | +| OctoScript 应用 | 通过准入的 `manifest.json` + `main.splash` bundle,由 App Hub 的 Card runner 解释执行。 | +| 宿主服务 | 按明确的调用应用身份执行某项操作并返回数据的 Rust 代码,不一定使用模型。 | +| 应用 Agent | octos 中按应用/账号限定的模型 Peer,拥有工作目录、会话及明确授予的工具。 | +| 系统 Agent | Shell 助手,拥有自己的工具策略和委派工具。 | +| ROM 特权 agent | 用于 Android 平台操作的 Java/Binder 服务,与模型驱动的系统 Agent 是不同组件。 | + +Rust `trait` 定义接口,`impl AppModule` 实现接口;`Widget` 处理事件和绘图。这些本身不意味着线程、LLM 或 Tokio 任务。Splash 既可描述原生控件,也可作为隔离应用程序;其权限取决于宿主和策略。这里的 `main.splash` 使用 Makepad Script/Splash;独立的 Octoscript L0 解析/检查器及 `.card` 转换路径不是该程序的解析器。“OctoScript 应用”是这些指南采用的产品名称,不表示两套语言实现相同。 + +## 2. 从最小原生例子开始 + +准备依赖后,在仓库根目录运行(**本次未验证**): + +```sh +# 独立的 Reference 窗口。 +cargo run --locked -p octosense-reference + +# 链接到桌面中,并在启动后打开。 +MAKEPAD_WM_TEST_APP=reference cargo run --locked -p octosense --features app-reference -- --module reference + +# 标准桌面产品。 +cargo run --locked --release -p octosense +``` + +无需占用屏幕时,添加 `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=8000`,通过 `/help` 描述的 Makepad 控制接口检查界面,并用 `/quit` 退出。`--module` 选择托管方式,`MAKEPAD_WM_TEST_APP` 请求启动应用。 + +按以下顺序读源码: + +1. [`apps/reference/src/lib.rs`](../../apps/reference/src/lib.rs):`ReferenceView` 保存 `count: usize`;`handle_event` 接收按钮和输入动作、更新标签;`draw_walk` 把绘图交给内部 `View`。这是普通 UI 状态,没有 Agent。 +2. 同文件的 `ReferenceModule`:`register` 注册控件类型;`create` 返回包含根控件、服务执行器和退出回调的 `InstanceParts`。执行器明确返回“Reference has no tools”。原生应用不会自动拥有 Agent。 +3. [`native-apps.json`](../../native-apps.json):声明 Reference 的源码、feature、托管、存储和空 Agent 授权。工具根据它生成注册表和 Cargo feature 区块,不要直接改生成部分。 +4. [`desktop/src/main.rs`](../src/main.rs):导入 Shell `App` 并调用 `octosense_main!`。在 [`crates/shell/src/lib.rs`](../../crates/shell/src/lib.rs) 中,该宏委托给 Makepad `app_main!` 并设置包目录。 +5. 同文件的 `App::launch_app_with_args`:查找应用,检查脚本应用身份和准入,准备存储,必要时聚焦已有窗口,再选择模块或进程托管。 +6. [`crates/shell/src/module_host.rs`](../../crates/shell/src/module_host.rs) 的 `ModuleHost::create`:准备实例范围、存储命名空间、回复句柄、视口和 VM,再创建模块。只有声明且获得策略授权的 Agent 服务才会注入。 + +进程托管继续看 [`crates/shell/src/clients.rs`](../../crates/shell/src/clients.rs) 和 [`crates/process-apps`](../../crates/process-apps)。Shell 启动子进程,连接窗口管理协议,转发输入并显示其画面。子进程与 octos Peer 是两个独立概念。Terminal 在 macOS/Windows 以及满足 Vulkan + Wayland 条件的 Linux 上通常走进程路径;模块回退和覆盖见[桌面 README](../README.zh-CN.md)。 + +## 3. 运行并追踪脚本 bundle + +标准桌面已包含选定的系统应用,可从启动器打开 News 或 Calendar。单独预览则使用 App Hub 仓库的 `card-host`;在准备好依赖的 App Hub 检出中运行(**本次未验证**): + +```sh +# 将示例路径换成你的 OctoSense 检出目录。 +cargo run --locked --release -p octosense-card-host --bin card-host -- --bundle /path/to/OctoSense/apps/news/bundle --system +``` + +`--system` 接纳内置 `os.*` bundle,但不会给预览器添加 Shell 的宿主服务和 Agent UI。Mail 需要 Shell 的服务,可以在 OctoSense 根目录启用演示邮箱(**本次未验证**): + +```sh +MAKEPAD_APP_CONFIG='{"mail_demo":true}' cargo run --locked --release -p octosense +``` + +演示账号的密码是 `demo`,发送留在演示环境。新商店应用在 OctoScript-App-Design-Flow 中开发,经 App Hub 准入和发布。用本地目录测试完整安装路径,见[桌面 README](../README.zh-CN.md)。 + +[`desktop/system-apps.json`](../system-apps.json) 和 [`phone/system-apps.json`](../../phone/system-apps.json) 选择 `apps/` 中的 bundle。再看 [`crates/shell/src/apps.rs`](../../crates/shell/src/apps.rs) 中的启动器条目、`agent_apps` 和 `register_host_services`。App Hub 的 `CARD_MODULE` 是这些解释执行程序的原生宿主,与需显式开启的 AppCard 助手模块不同。 + +manifest 请求能力,准入将其解析为策略。脚本的 `host.request(...)` 按应用身份检查;它既不是任意 Rust 调用,也不自动成为 LLM 工具调用。App Hub 的 `crates/appstore/src/services.rs` 定义 `HostService`、`ServiceCall` 和回复机制。调用携带应用身份和宿主目录,服务可以在执行前检查方法与调用者。 + +## 4. 用工具追踪真实数据 + +从 [`apps/calendar/bundle/tools.json`](../../apps/calendar/bundle/tools.json) 和 [`apps/calendar/host-service/src/lib.rs`](../../apps/calendar/host-service/src/lib.rs) 开始。JSON 声明工具和 schema,不包含实现。Rust `CalendarService` 实现宿主服务接口;`handle` 分派方法,`load`/`save` 管理 `/calendar/events.json`。 + +“添加日程”的调用链: + +```mermaid +sequenceDiagram + participant H as 人或系统 Agent + participant A as Calendar 应用 Agent + participant R as Shell 工具中继 + participant C as Calendar Rust 服务 + participant D as events.json + H->>A: 请求添加日程 + A->>R: calendar.add_event 和结构化参数 + R->>R: 检查调用者、授权、schema 和策略 + R->>C: 以 os.calendar 身份执行 + C->>D: 读取、校验并保存 + C-->>R: 对象结果(id/start) + R-->>A: 工具结果 + A-->>H: 回答原会话 +``` + +[`crates/shell/src/host_tools/script_apps.rs`](../../crates/shell/src/host_tools/script_apps.rs) 加载工具并实现 `HostServiceExecutor`;`host_tools/relay.rs` 负责授权。`calendar.remove_event` 是破坏性操作,需要配置的宿主确认。`calendar.notify`/`agenda` 填入固定 `.card` 模板,调用 `register_host_services` 安装的发布回调,Shell 检查 `glance` 授权。模型提供参数,不编写可执行卡片代码。 + +必须区分以下边界: + +| 边界 | 实际权限 | +| --- | --- | +| 脚本存储 | 应用的 storage 能力和隔离目录,仅使用运行时允许的 API。 | +| Agent 工作目录 | Peer 的应用/账号目录,仅能使用明确授予且受 Shell 策略限制的文件工具;不会挂载所有宿主服务数据库。 | +| 宿主服务数据库 | Rust 管理的 Calendar 日程、Mail 缓存与凭据、News 缓存等,经明确暴露的方法或工具访问;秘密保留在宿主界面和保险库中。 | + +当前例子并不相同:News 声明 `news.list` 和 `news.read`;Mail 的 **Agent 工具文件目前只有 `mail.notify`**,服务给 UI 提供的 `mail.list`、`mail.message`、`mail.send` 不会自动成为 Agent 工具。Calendar 窗口目前只是使用说明,不能通过脚本 `calendar` 能力列出或编辑日程,因为 App Hub 尚未提供该能力。 + +跨应用访问也要显式声明:请求方在 `agent.tools` 中列出带点号的工具名,所有者提供可共享工具,中继授权并以正确身份执行。App Hub 准入还检查 `HostLimits.offered_tools`;默认不提供 `mail.send` 等任意带点名称,因此只改 `agent.tools` 不会让 bundle 自动通过准入。可写工作目录或聊天消息都不能授予另一应用的文件、凭据或 API。系统 Agent 委派及应用反向请求系统 Agent 的当前限制,见配套架构导读。 + +## 5. 人如何直接与应用 Agent 对话 + +Shell 为启用 Agent 的应用绘制 **Ask <app>** 面板。桌面上聚焦应用后使用栏按钮、Shift+F8 或菜单的“Ask this app's agent”。首次授权后才准备 Peer。F8 打开系统 Agent,它通过 `agents.ask` 请求同意并准备 peer,然后用 `peer_send_input` 委派、`peer_gather` 获取结果;卡片中的 `sys.chat` 也可以联系所属应用 Agent。手机目前还没有打开该面板的触摸入口。 + +阅读 `crates/shell/src/app_chat/`、`system_chat/`、`agents.rs`、`crates/ai-host/src/contained.rs` 和 `crates/app-peers/`。人的对话和系统 Agent 的对话使用应用 Peer 上不同的 lane/session;面板 Stop 只中断人的那次运行。“一个 Peer”不等于“一份共享记录”“一个 OS 线程”或“一个 Tokio 任务”。Makepad 事件循环处理 UI,broker/内核和通知通过各自通道工作;配套导读继续映射到具体任务。 + +还必须配置内核:`octos-core` 链接集成代码,不会自动生成桌面的 `octos` 可执行程序或提供商凭据。配置兼容的 `OCTOS_APP_CORE_BIN`,在 AI providers 中配置模型,参阅[内核指南](../../crates/kernel/README.zh-CN.md)。Android 打包 `liboctos.so`;桌面和 Android 通常运行子进程内核,OpenHarmony 使用进程内内核。内核托管方式与应用 UI 的模块/进程托管是两回事。 + +## 6. Home 在共用 Shell 外加上设置 + +在 **`phone/` 中运行 Cargo**,其 `.cargo/config.toml` 会选择手机版 bundle。桌面预览配方(**本次未验证**): + +```sh +cargo run --locked --release -p octosense-home --features mobile-only +# 同时链接 Reference/Sheets;两个 feature 的职责不同。 +cargo run --locked --release -p octosense-home --features mobile-only,mobile-apps +``` + +[`phone/src/main.rs`](../../phone/src/main.rs) 的 `App` 包含 `#[deref] shell: ShellApp` 和 `SettingsRuntime`。解引用让代码可以访问 Shell 字段,并没有再启动一个 Shell 进程。`install_ext` 注册受信任的设置模块。`handle_event` 先处理设置的启动、计时和入口 intent,再让 Shell 处理事件,最后消费平台包和设置请求。调试丢失的更新时要注意这个顺序。 + +继续看 `phone/src/settings_app.rs`、`settings_script.rs` 和 `settings_script_host_facade.rs`:脚本控制器/UI 与 Rust 宿主校验配合。权限来自编译进来的受信任单例,不是脚本自称“settings”。`android_settings.rs` 根据 channel 分派观测结果和命令回复;已接受命令与随后观测到的平台状态不同,不能提前显示为已生效。 + +Android 路径继续进入 `phone/resources/android/java/dev/makepad/octosense/MakepadAppExtension.java`、其中调用的客户端和 `phone/android/contracts/`。System Bridge 的 `SystemBridgeService.java` 使用 Binder 回调和调用者检查。独立 Home 只有平台授予的权限/角色,安装 Home 不会获得 ROM 特权。[Home 构建说明](../../phone/README.zh-CN.md)介绍 APK 打包;桌面预览不能证明 Binder 或设备行为。 + +## 7. ROM 打包平台组件 + +阅读 [`rom/vendor/octosense/octosense.mk`](../../rom/vendor/octosense/octosense.mk) 和 `Android.bp` 中的产品配置,再看 [`rom/scripts/build-home.py`](../../rom/scripts/build-home.py)、`stage-home.py` 与 `stage-forks.sh`。构建产生 Home/Bridge APK 和回执,staging 校验并复制产物,LineageOS 构建产生镜像;安装、刷机、OTA 是另外的操作。 + +特权 Android 服务位于 `rom/vendor/octosense/agent/src/dev/makepad/octosense/agent/AgentPlatformService.java`。`caller` 检查 Binder UID、允许的包身份和平台签名;方法调用平台后端并返回能力/结果,AIDL 接口为 `IAgentPlatform.aidl`。它使用 Android 服务生命周期和 Binder 执行机制,不是 octos 模型循环,也不是 Rust Tokio 中的应用 Agent 任务。 + +Home 的 `AgentPlatformClient` 连接可选 ROM 服务。System Bridge、Quickstep、SystemUI、Settings broker 和特权 agent 是不同 Android 组件,不是任意应用都能调用的统一“系统 Agent”API。本次审查**未验证** ROM 启动和设备集成。 + +## 8. 单独理解较早的 AppCard 路径 + +`apps/appcard/module/src/lib.rs` 将可选 AppCard 助手适配为 `AppModule`;`apps/appcard/app/app` 实现 router/composer 和生成卡片,旁边是 transport/store/render crates。显式使用 `--features app-appcard` 开启;默认和 `mobile-apps` 不包含它。 + +AppCard 较早的路由/组合术语不等于所有当前系统/应用 Agent 的实现。系统聊天、应用聊天 broker 和隔离脚本 Agent 无需开启 AppCard;其旧 `personal-data` 邮箱读取器也不是当前 Mail 宿主服务的数据库 API。学习原生托管先看 Reference,学习已发布的应用工具先看 Calendar/News,修改这个可选产品时再看 AppCard。 diff --git a/docs/ai-services.md b/docs/ai-services.md index caba9c00..4f258d1a 100644 --- a/docs/ai-services.md +++ b/docs/ai-services.md @@ -2,7 +2,7 @@ English | [简体中文](ai-services.zh-CN.md) -How the assistant is wired into OctoSense: the [octos](https://github.com/octos-org/octos) agent kernel the shell runs, where the person configures it, which apps may use it and how, and what is planned. It describes `main` as of 2026-09-28 (OctoSense `ad0d738`, which pins octos `5e7577f0` and OctoSense-App-Hub `e8601b80`); on 2026-09-29 the statements about octos#2567, host tools and approvals, the peer link, the system chat and command execution were rechecked against OctoSense `baa90bd`, which pins octos `acffad3b` and the same App Hub. Everything under **Works today** was read in that code; **In progress** means an open pull request; **Planned** means an ADR or an open issue, with nothing merged yet. +How the assistant is wired into OctoSense: the octos kernel, provider configuration, app peers and tools. Current implementation statements were checked against OctoSense `c19da8d` (octos `ae230ce0`, App Hub `58c3c8ae`) on 2026-10-01. Earlier dated runs below are historical evidence, not validation of this revision. “Implemented” means present in the inspected source; it does not claim a device or real-provider run. For the call-by-call tutorial and execution model, read the [architecture walkthrough](architecture-walkthrough.md). This page is about the assistant *inside* OctoSense. Building an app needs no AI service and no particular coding agent: the app harness, [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow), works with any agent or none. Its [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) page is the app developer's short version of this one. @@ -25,16 +25,16 @@ For the whole system around it (processes per platform, agents, protocols, tools | One octos kernel per shell process, started on first use, restarted after a provider change | Works today (desktop with `OCTOS_APP_CORE_BIN`, Android, OpenHarmony; none on iOS) | [`crates/kernel`](../crates/kernel/README.md) | | AI providers: the person's model providers and keys, keys only on host sheets | Works today | [`apps/ai-providers`](../apps/ai-providers/host-service/README.md) | | The shell's AI entry point (`start`, policy, per-instance offer, QR import) | Works today | [`crates/ai-host`](../crates/ai-host/README.md) | -| Host-owned app peers: one octos peer per granted app, owned by the system agent | Works today, for native modules (Rinx) and, behind a switch, contained script apps | [`crates/app-peers`](../crates/app-peers/README.md), [Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | +| Host-owned app peers: one octos peer per granted app/account, owned by the system agent | Implemented for native modules (Rinx) and contained script apps after per-app consent | [`crates/app-peers`](../crates/app-peers/README.md), [Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | | AppCard ("Ask anything") on the shell's kernel | Works today, opt-in (`--features app-appcard`), not shipped | [`apps/appcard`](../apps/appcard) | -| A contained script app (system or store) asking the assistant | Works where the shell hosts a kernel ([#106](https://github.com/OctoSense-org/OctoSense/pull/106)): the `octos` host service gives each app its own peer (`card.`), while `Policy::contained_apps` is on (**off by default**; `OCTOSENSE_CONTAINED_APPS=1`) and after the person allows the app's agent at first use ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)). Tool approvals the peer raises are still declined. `llm` stays provider management for `os.*` apps only | [below](#contained-script-apps-system-and-store) | +| A contained script app (system or store) asking the assistant | Implemented through exact declared `octos.*` services, with a kernel and first-use consent by default. Host tools and kernel-tool approvals route through the shell. `OCTOSENSE_CONTAINED_APPS=0` disables access; `1` is a developer consent bypass, not normal setup | [below](#contained-script-apps-system-and-store) | | One-shot model calls for contained apps (`model`, `model.complete`) | Works today ([#95](https://github.com/OctoSense-org/OctoSense/pull/95)): registered by `crates/ai-host` with the `llm` service, for apps granted `model` ([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24), in the shells' App Hub pin) | [below](#contained-script-apps-system-and-store) | | News data service (`news`, no model) | Merged ([#69](https://github.com/OctoSense-org/OctoSense/pull/69)); answers `os.*` apps only | [`apps/news/host-service`](../apps/news/host-service/README.md) | -| `glance.publish`: L0 cards on the glance screen | Merged ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)); contained apps granted the `glance` capability publish ([#86](https://github.com/OctoSense-org/OctoSense/pull/86)). In progress: `sys.digest` sources ([#87](https://github.com/OctoSense-org/OctoSense/pull/87), draft) | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | +| `glance.publish`: L0 cards on the glance screen | Merged ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)); contained apps granted the `glance` capability publish ([#86](https://github.com/OctoSense-org/OctoSense/pull/86)). `sys.digest` integration is a separate runtime path; [#87](https://github.com/OctoSense-org/OctoSense/pull/87) is historical tracking, not a current PR-status claim | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | | Approvals, first-use consent, developer mode | Works today ([#120](https://github.com/OctoSense-org/OctoSense/pull/120), [#118](https://github.com/OctoSense-org/OctoSense/pull/118)): the shell's approval router, standing rules and sheets, fed by the AI services bus and by the kernel's `host_tool` approvals through the host-tool relay ([#145](https://github.com/OctoSense-org/OctoSense/pull/145)); consent before an app's agent first runs; developer mode turned on only by the person | [architecture § Approvals](architecture.md#5-approvals) | -| The system agent's tool set | Works today, enforced: octos's shell is never offered (the `_main` profile's `tool_policy`, [#117](https://github.com/OctoSense-org/OctoSense/pull/117)), and every kernel start sets the system session's exact kernel tool list (`session/tool_list/set`, octos#2648). Command execution is the Setup → Assistant → Command execution switch ([#132](https://github.com/OctoSense-org/OctoSense/pull/132)): `terminal.run`, each command approved live, only where the Terminal runs as its own process | [architecture § Tools and grants](architecture.md#4-tools-and-grants) | +| The system agent's tool set | Works today, enforced: octos's shell is never offered (the `_main` profile's `tool_policy`, [#117](https://github.com/OctoSense-org/OctoSense/pull/117)), and every kernel start sets the system session's exact kernel tool list (`session/tool_list/set`, octos#2648). Command execution is the Setup → Assistant → Command execution switch ([#132](https://github.com/OctoSense-org/OctoSense/pull/132)): `terminal.run`, each command approved live, in both module and process hosting where Terminal is available | [architecture § Tools and grants](architecture.md#4-tools-and-grants) | | Native apps declared once (`native-apps.json`), hosting per target; the Terminal a system app in its own process on the desktop | Works today ([#113](https://github.com/OctoSense-org/OctoSense/pull/113)) | [architecture § Native apps](architecture.md#native-apps-in-process-or-their-own-process) | -| An app's own agent: `tools.json`, `AGENT.md`, skills, model requirements, triggers | Planned ([ADR 0002](adr/0002-event-driven-app-agents.md), Proposed). App Hub admits the files ([App-Hub#18](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/18)); no shell runs them. The kernel side is merged ([octos#2567](https://github.com/octos-org/octos/pull/2567), in the pin), and the shell registers each peer's tools and relays its calls ([#145](https://github.com/OctoSense-org/OctoSense/pull/145)), but no app declares `tools.json` yet, so every peer registers an empty set | [below](#planned-event-driven-app-agents-adr-0002) | +| An app's own agent: declarations versus execution | `tools.json`, generic-tool grants, peers and host-service executors are implemented for News/Mail/Calendar. `AGENT.md` prompt loading, bundle skills/model selection and automatic triggers remain gaps | [below](#planned-event-driven-app-agents-adr-0002) | | Native apps in their own process reaching their agent (the peer link, ADR 0004 §5) | Built, no user yet. Makepad's client side ([OctoSense-org/makepad#54](https://github.com/OctoSense-org/makepad/pull/54), `makepad_ai_services::peer`) and the shell side ([#130](https://github.com/OctoSense-org/OctoSense/pull/130), `crates/shell/src/peer_link/`) are merged; no process app is granted an agent yet (the Terminal, the only process app, declares none) | [architecture § An app and its own agent](architecture.md#an-app-and-its-own-agent) | ## Architecture @@ -47,9 +47,10 @@ flowchart TB sheet["Host sheets
key, QR, PIN"] llm["llm host service
writes the provider profile"] aihost["crates/ai-host
start, policy, offer"] - broker["crates/app-peers broker
one peer per granted native app"] + broker["crates/app-peers broker
one peer per granted app/account"] runner["Card runner (App Hub)
host services: mail, news, glance, llm, model, octos"] router["Approval router
crates/shell/src/approvals"] + relay["Shell host-tool relay
declared tools and caller checks"] bus["AI services bus
crates/shell/src/ai_bus.rs"] rinx["Rinx (native module)"] appcard["AppCard (native, opt-in)"] @@ -72,23 +73,26 @@ flowchart TB runner -- "octos.* service
peer card.<app id>" --> broker rinx -- "typed tools" --> bus bus -- "confirm: host calls" --> router + kernel -- "peer/tool/call" --> relay + relay --> runner + kernel -- "approval/requested" --> router router --> person ``` ### The octos kernel: one per shell -The kernel is a **shell service** ([`crates/kernel`](../crates/kernel/README.md), package `octosense-kernel`), not an app. The shell configures it once at startup; nothing runs until the first consumer calls `octosense_kernel::connect()`, and later consumers share the same process. octos holds a single-writer lock on its data dir, so there is one kernel per core dir. When the last connection closes the kernel stops; `shutdown()` stops it with the shell (5 s at most). +The kernel is a **shell service** ([`crates/kernel`](../crates/kernel/README.md), package `octosense-kernel`), not an app. The shell configures it once at startup; nothing runs until the first consumer calls `octosense_kernel::connect()`, and later consumers share the same process. octos holds a single-writer lock on its data dir, so there is one kernel per core dir. In ordinary mode, when the last connection closes the kernel stops; Talk to Octos keeps the shared kernel alive while enabled; `shutdown()` stops it with the shell (5 s at most). How it runs, by platform (`crates/kernel/src/launch.rs`, `KernelSource::platform()` in `crates/ai-host`): | Platform | Kernel | Core dir (the octos home) | | --- | --- | --- | -| Desktop (macOS; Windows and Linux untested) | `$OCTOS_APP_CORE_BIN serve --stdio --data-dir ` (plus `--config /config.json` if present). **Without `OCTOS_APP_CORE_BIN` there is no kernel**, and a developer's own `octos serve` is never touched. Packaging the kernel next to the desktop binary is in progress ([#85](https://github.com/OctoSense-org/OctoSense/pull/85)). | `$OCTOS_APP_CORE_DIR`, else `/octos-home/.octos` (`~/.octosense/octos-home/.octos`): OctoSense's own, no longer the person's `~/octos-home/.octos`, whose provider settings it copies once | +| Desktop (macOS; Windows and Linux untested) | `$OCTOS_APP_CORE_BIN serve --stdio --data-dir ` (plus `--config /config.json` if present). **Without an explicit kernel program or `OCTOS_APP_CORE_BIN` there is no desktop kernel**, and a developer's own `octos serve` is never touched. Kernel packaging was tracked in [#85](https://github.com/OctoSense-org/OctoSense/pull/85); this recipe uses an explicit binary. | `$OCTOS_APP_CORE_DIR`, else `/octos-home/.octos` (`~/.octosense/octos-home/.octos`): OctoSense's own, no longer the person's `~/octos-home/.octos`, whose provider settings it copies once | | Android (Home) | The APK's `liboctos.so serve --stdio`, built by [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) from the octos revision the root `Cargo.toml` pins | `/octos-home/.octos` | | OpenHarmony | In process (`octos_cli::embedded::serve_io`), because a HAP may not exec | `/octos-home/.octos` | | iOS | **None.** Providers are still saved; no app gets an assistant | – | -Consumers speak the octos UI Protocol (JSON-RPC frames, as `octos serve --stdio` does) over a `Connection`. Each consumer gets the replies to its own requests and the notifications of its own sessions. When the providers change, the kernel restarts and every connection ends with `CloseReason::Restarted`; a consumer reconnects and reopens its sessions (AppCard's transport is the reference). +With Talk to Octos enabled, the kernel uses host-managed loopback WebSocket transport instead of stdio. Consumers speak the octos UI Protocol (JSON-RPC frames, as `octos serve --stdio` does) over a `Connection`. Each consumer gets the replies to its own requests and the notifications of its own sessions. When the providers change, the kernel restarts and every connection ends with `CloseReason::Restarted`; a consumer reconnects and reopens its sessions (AppCard's transport is the reference). ### AI providers and the `llm` host service @@ -105,21 +109,21 @@ It is a contained script app like any other; the privileged half is the **`llm` [`crates/ai-host`](../crates/ai-host/README.md) (`octosense-ai-host`) is what both shells call: `start(Host::platform(data_dir))` at startup (configures the kernel, installs the host policy, registers `llm` with the platform's QR import), `handle_event` every event, `offer(module, scope)` / `finish()` around a native module's `create`, and `shutdown()`. -The host **policy** decides which native modules may use the assistant, by exact `octos.*` service name, and whether contained apps get the `octos` service at all. `Policy::shipped()` grants only `rinx` the four services, and turns the contained apps' switch (`Policy::contained_apps`) on only with `OCTOSENSE_CONTAINED_APPS=1`. The person's per-app switch is **first-use consent** ([#120](https://github.com/OctoSense-org/OctoSense/pull/120), `crates/shell/src/approvals/consent.rs`): the first time an app asks for its agent the shell shows what it may read and use and where the model runs, and **Settings → Assistant → Approvals** lists every app's agent with an off switch ([architecture § Approvals](architecture.md#5-approvals)). +The host **policy** grants exact native `octos.*` services from the generated `native-apps.json` declarations (currently Rinx). `Policy::shipped()` enables contained apps behind **first-use consent** by default. `OCTOSENSE_CONTAINED_APPS=0` turns them off; `1` is a developer override that bypasses that consent gate while retaining declared-service limits. The shell asks on first use and provides per-app controls in Settings; see [Approvals](architecture.md#5-approvals). ### `crates/app-peers`: host-owned app peers [`crates/app-peers`](../crates/app-peers/README.md) is the broker between an app and the kernel (Rinx [ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md); kernel side octos UPCR-2026-034): -- A native module whose declared `octos.*` services the policy grants gets **one octos peer** for the app, created or resumed with `peer/prepare` on the shell's kernel. A module with nothing granted allocates no peer. +- A native module whose declared `octos.*` services the policy grants gets **one octos peer per account**, created or resumed with `peer/prepare` on the shell's kernel. A module with nothing granted allocates no peer. - The peer's **owner** is the shell's system agent session, `_main:api:octosense#system`. The kernel mints a host token for the peer; the shell keeps it in `/../app-peers` (0600), outside every app's reach. -- The peer's **memory namespace** is `app//acct-`: per app and per app account (the hash is a non-secret tag of the account id). The kernel provisions its workspace. A kernel without this contract is refused, never replaced by an ordinary session on the profile's memory. -- The app never sees the kernel protocol. It gets a scoped `OctosAppService` for the instance being created, binds its signed-in account, and opens one **request context** per client instance (`peer/context/open`). A change of account revokes every context of the old account; late events are dropped. -- The operations are `Open`, `History`, `Turn { text }`, `Interrupt` and `Approval { id, approve }`, each gated by its exact service (`octos.session.open`, `octos.session.history`, `octos.turn.start`, `octos.turn.interrupt`; an approval needs `octos.turn.start`). Turns time out after 180 s. +- The peer's **memory namespace** is `app//acct-`: per app and per app account (the hash is a non-secret tag of the account id). The shell selects the permitted account workspace; the kernel provisions and verifies it. A kernel without this contract is refused, never replaced by an ordinary session on the profile's memory. +- The app never sees the kernel protocol. It gets a scoped `OctosAppService` for the instance being created, binds its signed-in account, and opens one **request context** per client instance (`peer/context/open`). A request context is a distinct kernel session under the same peer, not another app peer. `open_conversation` creates the human lane with bounded shared history; the peer session handles system-delegated work. A change of account revokes every context of the old account; late events are dropped. +- The operations are `Open`, `History`, `Turn { text }`, `Interrupt` and `Approval { id, approve }`, each gated by its exact service (`octos.session.open`, `octos.session.history`, `octos.turn.start`, `octos.turn.interrupt`; an approval needs `octos.turn.start`). The broker default turn timeout is 180 s. ### The system agent -Today the system agent is the **owner** of every app peer: the session that created it and can address it. It does not hold any app's tools, and it cannot answer an app peer's approvals (octos [#2560](https://github.com/octos-org/octos/pull/2560)). Its tools are a defined set the shell writes before every kernel start, with octos's shell never offered ([#117](https://github.com/OctoSense-org/OctoSense/pull/117), `crates/kernel/src/system_tools.rs`; see [architecture § Tools and grants](architecture.md#4-tools-and-grants)). The person reaches it in the shell's **system chat** ([#132](https://github.com/OctoSense-org/OctoSense/pull/132), `crates/shell/src/system_chat/`: Setup → Assistant → Assistant chat, F8, the desktop dock's Assistant icon, or the phone home's Assistant tile; full screen on a phone), whose approvals go through the approval router, or from a Talk to Octos client ([#98](https://github.com/OctoSense-org/OctoSense/pull/98), [ADR 0003](adr/0003-shared-octos-client-access.md)). Its larger role in ADR 0002 (supervising app agents, budgets, the kill switch, ranking the glance screen, improving app agents) is **planned**; the glance screen currently orders cards by priority and recency. +The system agent owns the app peers and uses `peer_send_input` to delegate, then `peer_gather` to obtain results. `agents.list` discovers available app agents; `agents.ask` requests first-use consent/preparation, not the delegated task itself. The person reaches the system chat through F8 or the shell's Assistant entry (`crates/shell/src/system_chat/`), and can talk directly to an app through the desktop “Ask ” panel or a card's `sys.chat`. Phone touch navigation has no Ask-app panel entry yet. The system agent has a restricted kernel roster (`system_tools.rs`) and selected shell tools such as opt-in `terminal.run`; it does not inherit every app tool and cannot approve for the person. Talk to Octos is a separate client-access option. Automatic trigger orchestration, learning overlays and richer glance ranking remain planned; cards currently sort by priority and recency. ### Other assistants in the shell @@ -132,8 +136,8 @@ Today the system agent is the **owner** of every app peer: the session that crea | --- | --- | | **Keys stay with the host.** | Only the `llm` service reads or writes keys; they live in the platform vault or the owner-only profile under the kernel's core dir, never in an app's jail. The app-peers contract carries no credentials (`ModelInfo` has none). No `octos.*` service lets an app choose a provider or submit a key. | | **Secrets are the host's.** | No app collects a password, PIN, key or one-time code, not even to pass it on. The runtime makes a password field inert in a policed isolate, App Hub's gate refuses a bundle that declares one, and services ask on their own sheets (`.sheet.*` is accepted only from the sheet). | -| **Approvals belong to the person, in the owning app.** | A tool approval raised in an app's context is answered only by `ContextOp::Approval` from that app's own UI; the system agent never approves for an app (app-peers policy, octos #2560). Rinx's `send_message` shows the room and the exact text in Rinx's own sheet and sends only on the person's yes. The shell's approval router ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)) answers only on the person's gesture, live on a shell-drawn sheet or by a standing rule the person made; standing rules on "people in my contacts" use the person's contacts only after they turn on "Use my contacts in approval rules" ([architecture § Approvals](architecture.md#5-approvals)). Developer mode answers every approval for the apps it covers, and only the person turns it on ([#118](https://github.com/OctoSense-org/OctoSense/pull/118)). | -| **The system agent drives an app through its app agent.** | It owns the peers but holds no app tools; an app's tools run in the app (Rinx: `src/assistant`, "the system agent never holds these tools itself, it asks Rinx's peer"). | +| **Approvals belong to the person.** | The shell routes both `host_tool` and other kernel-tool approvals through its host-owned router; the app receives `approval/handled_by_host`. `confirm: app` uses an explicitly registered owning-app sheet. A system agent cannot approve for the person. Standing rules and developer mode are user-controlled; tool-specific restrictions still apply, including Terminal's non-auto-approvable command confirmation. See [Approvals](architecture.md#5-approvals). | +| **Delegation and tool execution have separate authority.** | The system agent delegates to app peers; the relay executes declared tools as their owner after grant/schema/policy checks. Cross-app direct tool grants are explicit, not access to all app APIs or databases. The system session separately has reviewed shell tools such as `terminal.run`. | | **Memory is private per app and account.** | Each peer's memory namespace is `app//acct-`; contexts of one account are never restored under another. Promotion to shared memory is planned (ADR 0002 §9). | | **Least privilege, by exact name.** | An app gets `declared ∩ supported ∩ host policy` services, compared by exact name: `octos.` or `octos.admin` grants nothing. | @@ -170,13 +174,14 @@ A script app runs in App Hub's Card runner and reaches the shell only through `h | Family | Who may call it | What it is | | --- | --- | --- | | `mail` | any app granted `mail` | Mail accounts the person signs in to on the host's sheet | +| `calendar` | Calendar's agent as `os.calendar`; no public script capability | Rust event storage and fixed glance-card tools. The script window currently shows instructions; it cannot call this family through a general Calendar capability. | | `llm` | `os.*` apps only | Managing the assistant's providers (`llm.providers`, `llm.add_provider`, `llm.test`, `llm.import_qr`, …); **no prompt or completion method** | -| `news` | `os.*` apps only (`may_call` in `apps/news/host-service/src/lib.rs`) | News's data service (feeds, ledger, `news.list`, `news.read`, …); no model. The shells' App Hub pin knows the `news` capability, but the News bundle does not declare it yet (`apps/news/bundle/manifest.json`), so it still fetches on its own | +| `news` | `os.*` apps only (`may_call` in the service) | News data, without a model. The News bundle now declares `news`; its agent exposes `news.list`/`news.read`. The background fetch timer does not yet trigger an LLM turn. | | `glance` | apps granted the `glance` capability ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) | Publishing L0 cards to the glance screen, under the app's own id (`crates/shell/src/glance.rs`) | | `model` | apps granted the `model` capability ([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24)) | One-shot `model.complete {task, input, schema, class?, allow_urls?}` and `model.budget` ([#95](https://github.com/OctoSense-org/OctoSense/pull/95), `apps/ai-providers/host-service/src/complete/`, registered in `crates/ai-host/src/lib.rs`): `class` `fast` or `strong`; the host picks the model from the person's providers, validates the reply against the schema, refuses URLs unless asked, keeps a per-app daily budget; no tools, memory or history, and the app never sees a key | -| `octos` | any app whose manifest declares the exact `octos.*` names, while the shell hosts a kernel, `Policy::contained_apps` is on (**off by default**; set `OCTOSENSE_CONTAINED_APPS=1` to try it) and the person allowed the app's agent at first use (`consent_for_contained`, [#120](https://github.com/OctoSense-org/OctoSense/pull/120)) | The assistant, through the app's own host-owned peer `card.` (`crates/ai-host/src/contained.rs`, [#106](https://github.com/OctoSense-org/OctoSense/pull/106)): the four `octos.*` calls with Rinx's argument rules (`octos.turn.start` takes only `text`, non-blank, at most 32 KiB; the others take `{}`). Tool approvals the peer raises are declined and listed in the reply's `denied_approvals` (the shell's approval router takes the kernel's `host_tool` approvals since #145, but not these other approvals of a contained app's peer); in developer mode they are answered for the apps it covers (`crates/app-peers/src/host_approvals.rs`). Replies over 2 MiB are refused | +| `octos` | Exact declared services, a kernel and first-use consent by default | Uses broker identity `card.` (the actual peer slug is returned by `peer/prepare`). `octos.turn.start` takes non-blank `text` up to 32 KiB and optional `trigger`/`from`; the other calls take `{}`. `trigger: "person"` is `AppSaysPerson`, an app assertion, not a trusted human gesture or approval bypass. Both host-tool and other peer approvals route to the shell; replies over 2 MiB are refused. | -So a contained app, store or system, reaches the assistant only through `octos.*`, in a shell that hosts a kernel. What it hears: +A script's own assistant calls use declared `octos.*` services. Separately, the shell can drive an app peer from `agent`/`tools.json` without the script declaring those UI calls. Replies on the script service path: | Call | Answer | | --- | --- | @@ -190,9 +195,9 @@ So a contained app, store or system, reaches the assistant only through `octos.* | `llm.*` from a store app granted `llm` | `llm is for OctoSense's own apps.` | | anything in App Hub's `card-host` | `no service answers "" on this device` (`card-host` registers no services) | -The first row, the `llm` row and the `card-host` row were run in `card-host` (App Hub `362d832`) on 2026-09-27. The reply, the unsupported-arguments answer and the missing-kernel answer were run on macOS on 2026-09-28 in a release desktop with hidden windows, through a system app declaring `octos.session.open` and `octos.turn.start` opened from the launcher; with a kernel built at the then-pinned octos `7bec0918` and the person's provider, the reply came from the peer `card.`, whose memory namespace `app/card./…` appeared in the kernel's data. The text-length and switch-off answers are covered by `cargo test -p octosense-ai-host`, through the same dispatch. OctoScript-App-Design-Flow's [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) has the example app and the argument and answer shapes of the four `octos.*` calls as Rinx serves them. +**Historical validation (not rerun for this revision).** The first row, the `llm` row and the `card-host` row were run in `card-host` (App Hub `362d832`) on 2026-09-27. The reply, the unsupported-arguments answer and the missing-kernel answer were run on macOS on 2026-09-28 in a release desktop with hidden windows, through a system app declaring `octos.session.open` and `octos.turn.start` opened from the launcher; with a kernel built at the then-pinned octos `7bec0918` and the person's provider, the reply came from the peer `card.`, whose memory namespace `app/card./…` appeared in the kernel's data. The text-length and switch-off answers are covered by `cargo test -p octosense-ai-host`, through the same dispatch. OctoScript-App-Design-Flow's [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) has the example app and the argument and answer shapes of the four `octos.*` calls as Rinx serves them. -The manifest's `agent` field (a permission profile, generic tools, iteration and token limits) is admitted and clamped by App Hub, but **nothing in the shells runs an agent for it**, and Rinx refuses to import a bundle that declares one. An app must not depend on it. +The manifest's `agent` and admitted `tools.json` participate in shell agent discovery, tool loading and grants. News/Mail/Calendar have working host-service-backed declarations. The `profile`/model requirements, `AGENT.md` prompt content, bundle skills and automatic triggers are not fully consumed; `implemented_by: "app"` has no script executor. Mail currently declares only `mail.notify`, not its UI's read/send methods. The agent workspace does not automatically expose host-service databases. Rinx mini-app admission is a separate contract; do not assume App Hub metadata is supported there. ## Planned: event-driven app agents (ADR 0002) @@ -200,23 +205,25 @@ The manifest's `agent` field (a permission profile, generic tools, iteration and | Piece | ADR | Status | | --- | --- | --- | -| `tools.json`: tools named `.`, JSON Schema input and output, `risk` (`read`, `act`, `destructive`), `confirm` (`host` or `app`), `background`, `shareable`, `implemented_by` (`host-service` or `app`) | §4, §12 | App Hub admits and pins it ([App-Hub#18](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/18), `crates/app-policy/src/agent.rs`). No shell loads it yet. | -| `AGENT.md`, data-only skills, model **requirements** (never a provider or model name), `background`, `triggers` (cron, host-service events) | §2, §3 | Same: admitted by App Hub (`crates/app-policy/src/agent.rs`), and the shells' App Hub pin `e8601b80` includes them. No shell runs them yet. | +| `tools.json`: names, input/output schemas, risk, confirmation, sharing and implementation | §4, §12 | Loaded by `host_tools/script_apps.rs`, registered on peers and routed to host-service executors. News, Mail and Calendar ship declarations. Arbitrary `implemented_by: "app"` script execution remains unavailable. | +| `AGENT.md`, data-only skills, model requirements, `background`, triggers | §2, §3 | Admitted metadata. Prompt/skill loading, model selection from these requirements and trigger scheduling remain unimplemented in the shell. Tool background eligibility alone does not schedule a turn. | | Kernel: host-registered tools per peer (`peer/tools/register`, `peer/tool/call`/`result`/`cancel`), tool-list and risk enforcement, approvals only on the host connection, an allowlist of generic tools, `peer/input` | §4, §13 | Kernel side merged: [octos#2567](https://github.com/octos-org/octos/pull/2567) (UPCR-2026-035), in the pin with its follow-ups (octos#2616). The shell side is on main: [#145](https://github.com/OctoSense-org/OctoSense/pull/145) (tool registration, the relay, `peer/input`) and G3 (per-app `generic_tools` from the manifests, `tools.json` loading, grants, executors for script apps' host services, schema and budget checks; `peer/input/reject`, octos#2621). | | Risk decides supervision: read and in-app act run unattended; destructive waits for the person (`confirm: host`: the kernel's approval path; `confirm: app`: the app's own sheet when the person is present, an approval request in the app's conversation when absent) | §4, §12 | Declared in App Hub (#18) and octos#2567. The shell's approval router, sheets and standing rules are merged ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)) and take the AI services bus's `confirm: host` calls; since [#145](https://github.com/OctoSense-org/OctoSense/pull/145) the kernel's `host_tool` approvals reach it through the relay ([architecture § Approvals](architecture.md#5-approvals)). Rinx's `send_message` already works the `confirm: app` way on its own surface. | | News M1: the `news` data service (no model) | First slice | Merged ([#69](https://github.com/OctoSense-org/OctoSense/pull/69)); issue [#60](https://github.com/OctoSense-org/OctoSense/issues/60). | -| News M2: `os.news` gets a peer and its tools are registered | First slice | Planned: [#61](https://github.com/OctoSense-org/OctoSense/issues/61). | +| News M2: `os.news` gets a peer and tools | First slice | Implemented: manifest `agent`, `news.list`/`news.read` tools, shell peer preparation and relay. | | News M3: triggers and an unattended run | First slice | Planned: [#62](https://github.com/OctoSense-org/OctoSense/issues/62). | -| News M4: glance cards (`glance.publish`, the glance page and desktop panel) | §7, §8 | `glance.publish` ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)) and the `glance` capability for contained apps ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), with [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) merged; in progress: `sys.digest` sources ([#87](https://github.com/OctoSense-org/OctoSense/pull/87), draft); issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63). | -| M5: the system toolbox (research, crawl) as granted tools | §6 | Planned: [#64](https://github.com/OctoSense-org/OctoSense/issues/64). Merged: the workflow templates ([#82](https://github.com/OctoSense-org/OctoSense/pull/82), `crates/toolbox`) and octos's research engine ([octos#2568](https://github.com/octos-org/octos/pull/2568)); in progress: offering the toolbox to app agents ([#108](https://github.com/OctoSense-org/OctoSense/pull/108), draft). | +| News M4: glance cards (`glance.publish`, the glance page and desktop panel) | §7, §8 | `glance.publish` ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)) and the `glance` capability for contained apps ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), with [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) merged; `sys.digest` integration has separate runtime/host requirements; [#87](https://github.com/OctoSense-org/OctoSense/pull/87) is historical tracking; issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63). | +| M5: the system toolbox as granted tools | §6 | Implemented behind `toolbox-peers`: `crates/ai-host/src/toolbox_peers.rs` and the shell toolbox executor. Home enables the feature by default; desktop opts in. Tools still require admission/grants and consent; this is not a general conversation with the system agent. | | M6: render and critique (`card-studio`) | §7 | App Hub's `card-studio` crate merged ([App-Hub#19](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/19)); the skill is planned ([#65](https://github.com/OctoSense-org/OctoSense/issues/65)). | -| M7: the per-app conversation (approvals, questions), memory | §9, §10 | Planned: [#66](https://github.com/OctoSense-org/OctoSense/issues/66). The shell-side approval sheets and consent exist ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)). | +| M7: app conversations, questions and memory | §9, §10 | Implemented human/system lanes, Ask-app panel, `sys.chat`, host-routed questions/approvals and scoped peer/context memory. See the [walkthrough](architecture-walkthrough.md). | | M8: the outer loop (overlays on `AGENT.md`) | §11 | Planned: [#67](https://github.com/OctoSense-org/OctoSense/issues/67). | The tracking issue is [#68](https://github.com/OctoSense-org/OctoSense/issues/68). App Hub's [PUBLISHING § The app's agent and tools](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.md#the-apps-agent-and-tools) has the file formats. ## Run and test locally +All commands below are **unverified in this documentation correction**; the walkthrough separately records the checks actually run. + ### Desktop, with a throwaway kernel and profile 1. Build octos at the revision the root `Cargo.toml` pins (`ae230ce0`), in a checkout of [octos-org/octos](https://github.com/octos-org/octos) (the flags are `tools/kernel-artifact.py`'s; **unverified** at this revision in this page's refresh): @@ -240,7 +247,7 @@ The tracking issue is [#68](https://github.com/OctoSense-org/OctoSense/issues/68 The log says `octos: kernel service ready (starts on first use), core dir …`. Without `OCTOS_APP_CORE_BIN` it says there is no kernel, and AI providers still saves providers. 3. Open **Start → Settings → AI providers**, add a model (family, model, route, key, **Test connection**, save). The profile is `$T/octos-home/.octos/profiles/_main.json`; with the file vault the key is in it, so delete `$T` afterwards. -4. Use the assistant through a consumer: Rinx (linked by default and in-process; open it from the launcher; sign in to Matrix, allow its agent on the first-use sheet, then use its assistant), or AppCard (`--features app-appcard`). A contained app reaches it through the `octos` host service ([above](#contained-script-apps-system-and-store)); add `OCTOSENSE_CONTAINED_APPS=1` to the command in step 2 and allow the app's agent when the shell asks. +4. Use the assistant through a consumer: Rinx (linked by default and in-process; open it from the launcher; sign in to Matrix, allow its agent on the first-use sheet, then use its assistant), or AppCard (`--features app-appcard`). A contained app reaches it through the `octos` host service ([above](#contained-script-apps-system-and-store)); leave `OCTOSENSE_CONTAINED_APPS` unset and allow the app's agent when the shell asks. F8 also opens the system chat; use `agents.ask` for consent/preparation, then `peer_send_input` for delegation. **Hidden windows.** Add `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=` to drive the shell over the remote bridge without taking the screen ([desktop README § Remote-control bridge](../desktop/README.md#remote-control-bridge)). `desktop/scripts/ai_providers_remote.sh` runs AI providers end to end this way with fake keys and outbound HTTPS denied, and `desktop/scripts/glance_remote.sh` does the same for the glance panel. diff --git a/docs/ai-services.zh-CN.md b/docs/ai-services.zh-CN.md index 7f44059d..b6529864 100644 --- a/docs/ai-services.zh-CN.md +++ b/docs/ai-services.zh-CN.md @@ -2,7 +2,7 @@ [English](ai-services.md) | 简体中文 -助手如何接入 OctoSense:Shell 运行的 [octos](https://github.com/octos-org/octos) Agent 内核、用户在哪里配置它、哪些应用可以使用以及如何使用,还有哪些在规划中。本文描述 2026-09-28 的 `main`(OctoSense `ad0d738`,它锁定 octos `5e7577f0` 和 OctoSense-App-Hub `e8601b80`)。标为**目前可用**的内容都在这份代码中读过;**进行中**表示有未合并的 pull request;**规划中**表示只有 ADR 或未关闭的 issue,尚无代码合入。 +本文介绍 OctoSense 的 octos 内核、提供方配置、应用 peer 和工具。当前实现说明已于 2026-10-01 对照 OctoSense `c19da8d`(octos `ae230ce0`、App Hub `58c3c8ae`)核查。下文较早的带日期运行记录是历史证据,不是此版本的验证。“已实现”表示所读源码中存在,不代表设备或真实提供方运行通过。逐步调用链与执行模型见[架构导读](architecture-walkthrough.zh-CN.md)。 本文讨论的是 OctoSense *内部*的助手。开发应用不需要任何 AI 服务,也不需要特定的编程 Agent:应用开发工具集 [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow) 适用于任何 Agent,也可以不用 Agent。它的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 页面是本文面向应用开发者的简短版本。 @@ -25,17 +25,17 @@ | 每个 Shell 进程一个 octos 内核,首次使用时启动,提供方变更后重启 | 目前可用(设置了 `OCTOS_APP_CORE_BIN` 的桌面端、Android、OpenHarmony;iOS 没有) | [`crates/kernel`](../crates/kernel/README.md) | | AI providers:用户的模型提供方和密钥,密钥只在宿主面板上输入 | 目前可用 | [`apps/ai-providers`](../apps/ai-providers/host-service/README.md) | | Shell 的 AI 入口(`start`、策略、按实例提供服务、QR 导入) | 目前可用 | [`crates/ai-host`](../crates/ai-host/README.md) | -| 宿主拥有的应用 peer:每个获授权的应用一个 octos peer,归系统 Agent 所有 | 目前可用:原生模块(Rinx),以及在开关打开时的隔离脚本应用 | [`crates/app-peers`](../crates/app-peers/README.md)、[Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | +| 宿主拥有的应用 peer:每个获授权的应用/账号一个 octos peer,归系统 Agent 所有 | 已实现:原生模块(Rinx)及经过按应用同意的隔离脚本应用 | [`crates/app-peers`](../crates/app-peers/README.md)、[Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | | 在 Shell 内核上运行的 AppCard("Ask anything") | 目前可用,需主动开启(`--features app-appcard`),不随产品发布 | [`apps/appcard`](../apps/appcard) | -| 隔离运行的脚本应用(系统应用或商店应用)向助手提问 | 在托管了内核的 Shell 中可用([#106](https://github.com/OctoSense-org/OctoSense/pull/106)):`octos` 宿主服务为每个应用分配自己的 peer(`card.<应用 id>`),前提是 `Policy::contained_apps` 为开(**默认关闭**;`OCTOSENSE_CONTAINED_APPS=1`),且用户在首次使用时允许了该应用的 Agent([#120](https://github.com/OctoSense-org/OctoSense/pull/120))。peer 发起的工具审批仍会被拒绝。`llm` 仍是只供 `os.*` 应用使用的提供方管理服务 | [见下文](#隔离运行的脚本应用系统应用和商店应用) | +| 隔离脚本应用向助手提问 | 已实现:精确声明的 `octos.*` 服务、内核与默认的首次使用同意;宿主工具和内核工具审批都交给 Shell。`OCTOSENSE_CONTAINED_APPS=0` 禁用;`1` 是跳过同意的开发覆盖,不是正常设置步骤 | [见下文](#隔离运行的脚本应用系统应用和商店应用) | | 供隔离应用使用的一次性模型调用(`model`,`model.complete`) | 目前可用([#95](https://github.com/OctoSense-org/OctoSense/pull/95)):由 `crates/ai-host` 与 `llm` 服务一同注册,供获得 `model` 权限的应用使用([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24),已在 Shell 锁定的 App Hub 中) | [见下文](#隔离运行的脚本应用系统应用和商店应用) | | News 数据服务(`news`,不使用模型) | 已合入([#69](https://github.com/OctoSense-org/OctoSense/pull/69));只响应 `os.*` 应用 | [`apps/news/host-service`](../apps/news/host-service/README.md) | -| `glance.publish`:glance 屏幕上的 L0 卡片 | 已合入([#72](https://github.com/OctoSense-org/OctoSense/pull/72));获得 `glance` 权限的隔离应用可以发布([#86](https://github.com/OctoSense-org/OctoSense/pull/86))。进行中:`sys.digest` 数据源([#87](https://github.com/OctoSense-org/OctoSense/pull/87),草稿) | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | -| 审批、首次使用同意、开发者模式 | 目前可用([#120](https://github.com/OctoSense-org/OctoSense/pull/120)、[#118](https://github.com/OctoSense-org/OctoSense/pull/118)):Shell 的审批路由、常设规则和审批面板,目前只接收 AI 服务总线的调用;应用的 Agent 首次运行前征求同意;开发者模式只能由用户打开 | [架构 § 审批](architecture.zh-CN.md#5-审批) | -| 系统 Agent 的工具集 | 目前可用,已强制:从不提供 octos 的 shell(`_main` profile 的 `tool_policy`,[#117](https://github.com/OctoSense-org/OctoSense/pull/117)),且每次内核启动都设置系统会话的精确内核工具列表(`session/tool_list/set`,octos#2648) | [架构 § 工具与授权](architecture.zh-CN.md#4-工具与授权) | +| `glance.publish`:glance 屏幕上的 L0 卡片 | 已合入([#72](https://github.com/OctoSense-org/OctoSense/pull/72));获得 `glance` 权限的隔离应用可以发布([#86](https://github.com/OctoSense-org/OctoSense/pull/86))。`sys.digest` 有单独的运行时/宿主要求;[#87](https://github.com/OctoSense-org/OctoSense/pull/87) 是历史跟踪链接,不表示当前 PR 状态 | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | +| 审批、首次使用同意、开发者模式 | 已实现:Shell 审批路由、常设规则及面板接收 AI 服务总线和内核工具审批;首次运行先征求同意,开发者模式由用户开启 | [架构 § 审批](architecture.zh-CN.md#5-审批) | +| 系统 Agent 的工具集 | 已强制:不提供 octos 内置 shell;精确设置系统会话内核工具列表。用户开启命令执行后通过 `terminal.run`,每次命令实时确认;Terminal 可用时模块和进程托管均支持 | [架构 § 工具与授权](architecture.zh-CN.md#4-工具与授权) | | 原生应用只声明一次(`native-apps.json`),按目标平台决定托管方式;Terminal 作为系统应用在桌面端以独立进程运行 | 目前可用([#113](https://github.com/OctoSense-org/OctoSense/pull/113)) | [架构 § 原生应用](architecture.zh-CN.md#原生应用进程内还是独立进程) | -| 应用自己的 Agent:`tools.json`、`AGENT.md`、skills、模型需求、触发器 | 规划中([ADR 0002](adr/0002-event-driven-app-agents.md),Proposed)。App Hub 接受这些文件([App-Hub#18](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/18));没有 Shell 运行它们;内核一侧进行中([octos#2567](https://github.com/octos-org/octos/pull/2567),草稿) | [见下文](#规划中事件驱动的应用-agentadr-0002) | -| 独立进程中的原生应用访问自己的 Agent(peer link,ADR 0004 §5) | 规划中(计划第 8 步)。Makepad 的客户端一侧已合入([OctoSense-org/makepad#54](https://github.com/OctoSense-org/makepad/pull/54),`makepad_ai_services::peer`);Shell 一侧尚未实现(`crates/shell/src/hub.rs` 中没有) | [架构 § 应用与它自己的 Agent](architecture.zh-CN.md#应用与它自己的-agent) | +| 应用自己的 Agent:声明与执行 | News/Mail/Calendar 的 `tools.json`、通用工具授权、peer 和宿主服务执行器已实现。`AGENT.md` 提示词加载、包内 skills/模型选择和自动触发器仍有缺口 | [见下文](#规划中事件驱动的应用-agentadr-0002) | +| 独立进程中的原生应用访问自己的 Agent(peer link) | Makepad 客户端与 Shell `crates/shell/src/peer_link/` 均已实现。当前没有进程应用申请自己的 Agent;Terminal 声明了工具但未申请 peer | [架构 § 应用与它自己的 Agent](architecture.zh-CN.md#应用与它自己的-agent) | ## 架构 @@ -47,9 +47,10 @@ flowchart TB sheet["宿主面板
密钥、QR、PIN"] llm["llm 宿主服务
写入提供方配置"] aihost["crates/ai-host
start、策略、offer"] - broker["crates/app-peers broker
每个获授权的原生应用一个 peer"] + broker["crates/app-peers broker
每个获授权的应用/账号一个 peer"] runner["Card runner(App Hub)
宿主服务:mail、news、glance、llm、model、octos"] router["审批路由
crates/shell/src/approvals"] + relay["Shell 宿主工具 relay
声明和调用者检查"] bus["AI 服务总线
crates/shell/src/ai_bus.rs"] rinx["Rinx(原生模块)"] appcard["AppCard(原生,需主动开启)"] @@ -72,23 +73,26 @@ flowchart TB runner -- "octos.* 服务
peer card.<应用 id>" --> broker rinx -- "类型化工具" --> bus bus -- "confirm: host 调用" --> router + kernel -- "peer/tool/call" --> relay + relay --> runner + kernel -- "approval/requested" --> router router --> person ``` ### octos 内核:每个 Shell 一个 -内核是一个 **Shell 服务**([`crates/kernel`](../crates/kernel/README.md),包名 `octosense-kernel`),不是应用。Shell 在启动时配置一次;在第一个使用者调用 `octosense_kernel::connect()` 之前什么都不运行,之后的使用者共享同一个进程。octos 对它的数据目录持有单写者锁,所以每个 core 目录只有一个内核。最后一个连接关闭时内核停止;`shutdown()` 随 Shell 一起停止它(最多 5 秒)。 +内核是一个 **Shell 服务**([`crates/kernel`](../crates/kernel/README.md),包名 `octosense-kernel`),不是应用。Shell 在启动时配置一次;在第一个使用者调用 `octosense_kernel::connect()` 之前什么都不运行,之后的使用者共享同一个进程。octos 对它的数据目录持有单写者锁,所以每个 core 目录只有一个内核。普通模式下最后一个连接关闭时内核停止;Talk to Octos 开启期间会保持共享内核存活;`shutdown()` 随 Shell 一起停止它(最多 5 秒)。 各平台的运行方式(`crates/kernel/src/launch.rs`,`crates/ai-host` 中的 `KernelSource::platform()`): | 平台 | 内核 | Core 目录(octos home) | | --- | --- | --- | -| 桌面端(macOS;Windows 和 Linux 未测试) | `$OCTOS_APP_CORE_BIN serve --stdio --data-dir `(存在 `/config.json` 时再加 `--config`)。**没有 `OCTOS_APP_CORE_BIN` 就没有内核**,开发者自己运行的 `octos serve` 永远不会被动到。把内核打包在桌面端二进制旁边的工作正在进行([#85](https://github.com/OctoSense-org/OctoSense/pull/85))。 | `$OCTOS_APP_CORE_DIR`,否则为 `/octos-home/.octos`(`~/.octosense/octos-home/.octos`):OctoSense 自己的目录,不再是用户的 `~/octos-home/.octos`(只从中复制一次提供商设置) | +| 桌面端(macOS;Windows 和 Linux 未测试) | `$OCTOS_APP_CORE_BIN serve --stdio --data-dir `(存在 `/config.json` 时再加 `--config`)。**未显式指定内核程序或 `OCTOS_APP_CORE_BIN` 时没有桌面内核**,开发者自己运行的 `octos serve` 永远不会被动到。[#85](https://github.com/OctoSense-org/OctoSense/pull/85) 是内核打包的历史跟踪;此配方显式指定二进制。 | `$OCTOS_APP_CORE_DIR`,否则为 `/octos-home/.octos`(`~/.octosense/octos-home/.octos`):OctoSense 自己的目录,不再是用户的 `~/octos-home/.octos`(只从中复制一次提供商设置) | | Android(Home) | APK 中的 `liboctos.so serve --stdio`,由 [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) 按根 `Cargo.toml` 锁定的 octos 版本构建 | `<应用数据目录>/octos-home/.octos` | | OpenHarmony | 进程内运行(`octos_cli::embedded::serve_io`),因为 HAP 不能 exec | `<应用数据目录>/octos-home/.octos` | | iOS | **没有。** 提供方仍会保存;没有应用能获得助手 | – | -使用者通过 `Connection` 使用 octos UI Protocol(JSON-RPC 帧,与 `octos serve --stdio` 相同)。每个使用者只收到自己请求的回复和自己会话的通知。提供方变更时内核重启,所有连接以 `CloseReason::Restarted` 结束;使用者重新连接并重新打开会话(AppCard 的传输层是参考实现)。 +开启 Talk to Octos 后,内核使用宿主管理的回环 WebSocket 代替 stdio。使用者通过 `Connection` 使用 octos UI Protocol(JSON-RPC 帧,与 `octos serve --stdio` 相同)。每个使用者只收到自己请求的回复和自己会话的通知。提供方变更时内核重启,所有连接以 `CloseReason::Restarted` 结束;使用者重新连接并重新打开会话(AppCard 的传输层是参考实现)。 ### AI providers 与 `llm` 宿主服务 @@ -105,21 +109,21 @@ flowchart TB [`crates/ai-host`](../crates/ai-host/README.md)(`octosense-ai-host`)是两个 Shell 都调用的入口:启动时调用 `start(Host::platform(data_dir))`(配置内核、安装宿主策略、注册带平台 QR 导入能力的 `llm`),每个事件调用 `handle_event`,在原生模块 `create` 前后调用 `offer(module, scope)` / `finish()`,退出时调用 `shutdown()`。 -宿主**策略**按精确的 `octos.*` 服务名决定哪些原生模块可以使用助手,以及隔离应用是否能使用 `octos` 服务。`Policy::shipped()` 只把这四个服务授予 `rinx`,并且只有设置 `OCTOSENSE_CONTAINED_APPS=1` 时才打开隔离应用的开关(`Policy::contained_apps`)。用户按应用的开关是**首次使用同意**([#120](https://github.com/OctoSense-org/OctoSense/pull/120),`crates/shell/src/approvals/consent.rs`):应用第一次请求它的 Agent 时,Shell 显示它可以读取和使用什么、模型在哪里运行;**设置 → 助手 → 审批**列出每个应用的 Agent,并带有关闭开关([架构 § 审批](architecture.zh-CN.md#5-审批))。 +宿主**策略**从 `native-apps.json` 生成的声明读取原生 `octos.*` 精确授权(目前是 Rinx)。`Policy::shipped()` 默认让隔离应用在**首次使用同意**后获得 Agent。`OCTOSENSE_CONTAINED_APPS=0` 关闭,`1` 是绕过该同意门槛的开发覆盖,但仍受已声明服务的限制。Shell 首次使用时询问,设置中提供按应用控制,见[审批](architecture.zh-CN.md#5-审批)。 ### `crates/app-peers`:宿主拥有的应用 peer [`crates/app-peers`](../crates/app-peers/README.md) 是应用和内核之间的中介(Rinx [ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md);内核一侧是 octos UPCR-2026-034): -- 原生模块声明的 `octos.*` 服务获得策略授权后,该应用会在 Shell 的内核上得到**一个 octos peer**,通过 `peer/prepare` 创建或恢复。没有获得任何授权的模块不会分配 peer。 +- 原生模块声明的 `octos.*` 服务获得策略授权后,该应用会在 Shell 的内核上得到**每个账号一个 octos peer**,通过 `peer/prepare` 创建或恢复。没有获得任何授权的模块不会分配 peer。 - peer 的**所有者**是 Shell 的系统 Agent 会话 `_main:api:octosense#system`。内核为 peer 生成宿主 token;Shell 把它保存在 `/../app-peers`(0600),任何应用都无法访问。 -- peer 的**记忆命名空间**是 `app//acct-`:按应用和应用账号区分(hash 是账号 id 的非机密标签)。内核为它提供工作区。不支持这一约定的内核会被拒绝,绝不会退回到使用配置共享记忆的普通会话。 -- 应用永远看不到内核协议。它为正在创建的实例拿到一个受限的 `OctosAppService`,绑定已登录的账号,并为每个客户端实例打开一个**请求上下文**(`peer/context/open`)。切换账号会撤销旧账号的所有上下文;迟到的事件会被丢弃。 -- 操作包括 `Open`、`History`、`Turn { text }`、`Interrupt` 和 `Approval { id, approve }`,每个都受对应的精确服务名约束(`octos.session.open`、`octos.session.history`、`octos.turn.start`、`octos.turn.interrupt`;审批需要 `octos.turn.start`)。一个回合 180 秒后超时。 +- peer 的**记忆命名空间**是 `app//acct-`:按应用和应用账号区分(hash 是账号 id 的非机密标签)。Shell 选择获准的账号工作目录,内核创建并核验。不支持这一约定的内核会被拒绝,绝不会退回到使用配置共享记忆的普通会话。 +- 应用永远看不到内核协议。它为正在创建的实例拿到一个受限的 `OctosAppService`,绑定已登录的账号,并为每个客户端实例打开一个**请求上下文**(`peer/context/open`)。请求上下文是同一 peer 下独立的内核 session,不是另一个应用 peer。`open_conversation` 创建带有限共享历史的人类通道,peer session 处理系统委派。切换账号会撤销旧账号的所有上下文;迟到的事件会被丢弃。 +- 操作包括 `Open`、`History`、`Turn { text }`、`Interrupt` 和 `Approval { id, approve }`,每个都受对应的精确服务名约束(`octos.session.open`、`octos.session.history`、`octos.turn.start`、`octos.turn.interrupt`;审批需要 `octos.turn.start`)。broker 默认回合超时为 180 秒。 ### 系统 Agent -目前系统 Agent 是所有应用 peer 的**所有者**:创建它们并能与之通信的会话。它不持有任何应用的工具,也无法回答应用 peer 的审批(octos [#2560](https://github.com/octos-org/octos/pull/2560))。它的工具是 Shell 在每次启动内核前写入的一个确定集合,从不提供 octos 的 shell([#117](https://github.com/OctoSense-org/OctoSense/pull/117),`crates/kernel/src/system_tools.rs`;见[架构 § 工具与授权](architecture.zh-CN.md#4-工具与授权))。目前用户通过 Talk to Octos 客户端与它对话([#98](https://github.com/OctoSense-org/OctoSense/pull/98),[ADR 0003](adr/0003-shared-octos-client-access.md));Shell 还没有为它绘制自己的对话界面。它在 ADR 0002 中更大的角色(监督应用 Agent、预算、紧急停止、对 glance 屏幕排序、改进应用 Agent)还在**规划中**;glance 屏幕目前按优先级和时间排序卡片。 +系统 Agent 拥有应用 peer,通过 `peer_send_input` 委派任务,再用 `peer_gather` 获取结果。`agents.list` 发现应用 Agent;`agents.ask` 请求首次同意并准备 peer,本身不发送委派任务。用户可用 F8 或 Shell 的 Assistant 入口打开系统聊天(`crates/shell/src/system_chat/`),也可通过桌面 “Ask ” 面板或卡片 `sys.chat` 直接与应用 Agent 对话;手机尚无打开 Ask-app 面板的触控入口。系统 Agent 使用受限内核工具列表和审核过的 Shell 工具(例如需开启的 `terminal.run`),不会继承所有应用工具,也不能替用户审批。Talk to Octos 是另一种客户端入口。自动触发调度、学习 overlay 和更丰富的 glance 排序仍在规划中;卡片目前按优先级和时间排序。 ### Shell 中的其他助手 @@ -132,8 +136,8 @@ flowchart TB | --- | --- | | **密钥留在宿主。** | 只有 `llm` 服务读写密钥;密钥保存在平台密钥存储或内核 core 目录下仅所有者可读的配置中,从不进入应用的 jail。app-peers 约定中不携带任何凭据(`ModelInfo` 中没有)。没有任何 `octos.*` 服务允许应用选择提供方或提交密钥。 | | **机密归宿主所有。** | 应用不收集密码、PIN、密钥或一次性验证码,即使只是转交也不行。运行时让受管控隔离环境中的密码输入框失效,App Hub 的准入检查拒绝声明了此类输入框的应用包,服务在自己的面板上询问(`.sheet.*` 只接受来自面板的调用)。 | -| **审批属于用户,在所属应用中进行。** | 应用上下文中发起的工具审批只能由该应用自己的界面通过 `ContextOp::Approval` 回答;系统 Agent 从不替应用审批(app-peers 策略,octos #2560)。Rinx 的 `send_message` 会在 Rinx 自己的面板上显示房间和确切文字,只有用户确认才发送。Shell 的审批路由([#120](https://github.com/OctoSense-org/OctoSense/pull/120))只凭用户的操作作答:在 Shell 绘制的面板上当场确认,或按用户自己建立的常设规则;“我的联系人”类规则只有在用户打开“在审批规则中使用我的联系人”之后才会使用联系人([架构 § 审批](architecture.zh-CN.md#5-审批))。开发者模式为它覆盖的应用回答所有审批,只能由用户打开([#118](https://github.com/OctoSense-org/OctoSense/pull/118))。 | -| **系统 Agent 通过应用的 Agent 驱动应用。** | 它拥有 peer,但不持有应用工具;应用的工具在应用中运行(Rinx:`src/assistant`,“系统 Agent 自己从不持有这些工具,而是请求 Rinx 的 peer”)。 | +| **审批属于用户。** | Shell 将 `host_tool` 以及其他内核工具审批交给宿主路由,应用只收到 `approval/handled_by_host`。`confirm: app` 使用明确注册的所属应用面板。系统 Agent 不能代替用户同意;常设规则和开发者模式由用户控制,仍受工具限制,例如 Terminal 命令不能自动批准。见[审批](architecture.zh-CN.md#5-审批)。 | +| **委派和工具执行的权限不同。** | 系统 Agent 委派给应用 peer;relay 检查授权、schema 和策略后以所有者身份执行工具。跨应用工具授权必须明确,不是获得所有 API 或数据库;系统会话另有审核过的 Shell 工具,如 `terminal.run`。 | | **记忆按应用和账号私有。** | 每个 peer 的记忆命名空间是 `app//acct-`;一个账号的上下文从不在另一个账号下恢复。提升到共享记忆还在规划中(ADR 0002 §9)。 | | **最小权限,按精确名称。** | 应用得到的是 `声明 ∩ 支持 ∩ 宿主策略` 的服务,按精确名称比较:`octos.` 或 `octos.admin` 不授予任何权限。 | @@ -159,7 +163,7 @@ flowchart TB 4. `availability()` 报告 `Unavailable`(没有内核、未授权、未登录)、`Idle`、`Ready` 或 `Failed`;在任何状态下应用的普通界面都照常工作。`settings_entry()` 为 `Host`:应用不提供自己的提供方表单,而是引导用户去 AI providers。 -**工具。** Rinx 只定义一次它的助手工具(`status`、`list_rooms`、`open_room`、`draft_message`、`read_room`、`open_mini_app`、`send_message`;`src/assistant/mod.rs`)。目前 Shell 通过 AI 服务总线上 Rinx 的 `ServiceExecutor` 调用它们。`read_room` 会在 Rinx 的读取面板上请求按房间的授权;`send_message` 是 Destructive 且自行确认:Rinx 的发送面板就是唯一的一次确认。把这些工具注册到 Rinx 的 octos peer、让 peer 自己的模型能调用它们,要等内核支持宿主注册工具([octos#2567](https://github.com/octos-org/octos/pull/2567),尚未合并)。 +**工具。** Rinx 在 `src/assistant/mod.rs` 定义其 UI 助手工具,通过 AI 服务总线上的 `ServiceExecutor` 执行,读取和发送仍走自己的确认界面。内核宿主注册工具及 Shell relay 已实现,缺口不是等待 octos#2567 合并:当前 Rinx 原生清单未声明这些 peer 工具,也尚未通过 `OctosAppService::set_confirm_sheet` 将发送确认面板交给 Shell。因此不要把总线上能调用的工具当作 Rinx peer 已拥有的工具。 **Rinx 迷你应用。** Rinx 托管经过审核的 OctoScript 迷你应用,并向它们提供同样的四个 `octos.*` 服务,每个运行中的实例使用 Rinx peer 的一个独立请求上下文([示例](https://github.com/hagency-org/Rinx/tree/main/examples/miniapps/matrix-octos-script))。这是 Rinx 自己的迷你应用宿主,适用于用户审核后导入 Rinx 的应用包;它不是 App Hub 的安装路径。 @@ -170,13 +174,14 @@ flowchart TB | Family | 谁可以调用 | 是什么 | | --- | --- | --- | | `mail` | 获得 `mail` 授权的任何应用 | 用户在宿主面板上登录的邮件账号 | +| `calendar` | Calendar Agent 以 `os.calendar` 身份调用;无公开脚本能力 | Rust 日程存储和固定 glance 卡片工具;脚本窗口目前只是说明,不能通过通用 Calendar 能力调用这个 family。 | | `llm` | 仅 `os.*` 应用 | 管理助手的提供方(`llm.providers`、`llm.add_provider`、`llm.test`、`llm.import_qr` 等);**没有提示词或补全方法** | -| `news` | 仅 `os.*` 应用(`apps/news/host-service/src/lib.rs` 中的 `may_call`) | News 的数据服务(订阅源、已读记录、`news.list`、`news.read` 等),不使用模型。Shell 锁定的 App Hub 已认识 `news` 权限,但 News 应用包还没有声明它(`apps/news/bundle/manifest.json`),所以仍自己抓取 | +| `news` | 仅 `os.*` 应用(服务的 `may_call`) | 不使用模型的 News 数据服务。News bundle 已声明 `news`,其 Agent 暴露 `news.list`/`news.read`;后台抓取计时器尚不会启动 LLM 回合。 | | `glance` | 获得 `glance` 权限的应用([#86](https://github.com/OctoSense-org/OctoSense/pull/86)、[App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) | 以应用自己的 id 向 glance 屏幕发布 L0 卡片(`crates/shell/src/glance.rs`) | | `model` | 获得 `model` 权限的应用([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24)) | 一次性的 `model.complete {task, input, schema, class?, allow_urls?}` 和 `model.budget`([#95](https://github.com/OctoSense-org/OctoSense/pull/95),`apps/ai-providers/host-service/src/complete/`,在 `crates/ai-host/src/lib.rs` 中注册):`class` 为 `fast` 或 `strong`;宿主从用户的提供方中挑选模型,按 schema 校验回复,除非请求否则拒绝含 URL 的回复,按应用管理每日预算;没有工具、记忆和历史,应用也看不到任何密钥 | -| `octos` | manifest 声明了确切 `octos.*` 名称的任何应用;前提是 Shell 托管了内核、`Policy::contained_apps` 为开(**默认关闭**;设置 `OCTOSENSE_CONTAINED_APPS=1` 可试用),且用户在首次使用时允许了该应用的 Agent(`consent_for_contained`,[#120](https://github.com/OctoSense-org/OctoSense/pull/120)) | 助手:经应用自己的、由宿主拥有的 peer `card.<应用 id>`(`crates/ai-host/src/contained.rs`,[#106](https://github.com/OctoSense-org/OctoSense/pull/106))。四个 `octos.*` 调用沿用 Rinx 的参数规则(`octos.turn.start` 只接受 `text`,非空白、最多 32 KiB;其余只接受 `{}`)。peer 发起的工具审批会被拒绝并列在回复的 `denied_approvals` 中(在 octos#2567 之前,Shell 的审批路由不接收内核审批);开发者模式下由它为覆盖的应用作答(`crates/app-peers/src/host_approvals.rs`)。超过 2 MiB 的回复会被拒绝 | +| `octos` | 精确声明的服务、内核及默认的首次使用同意 | broker 身份为 `card.<应用 id>`,真实 peer slug 由 `peer/prepare` 返回。`octos.turn.start` 接受非空白、最多 32 KiB 的 `text` 和可选 `trigger`/`from`;其余调用接受 `{}`。`trigger: "person"` 是 `AppSaysPerson`,只是应用声明,不是受信任的人类操作或绕过审批的凭证。宿主工具和其他 peer 审批都交给 Shell;超过 2 MiB 的回复拒绝。 | -因此,隔离运行的应用(商店应用或系统应用)只能通过 `octos.*` 使用助手,且需要 Shell 托管了内核。它会收到: +脚本自己的助手调用使用已声明的 `octos.*`;Shell 也可以根据 `agent`/`tools.json` 驱动 peer,而不要求脚本声明这些 UI 调用。脚本服务调用的回复: | 调用 | 返回 | | --- | --- | @@ -190,9 +195,9 @@ flowchart TB | 获得 `llm` 授权的商店应用调用 `llm.*` | `llm is for OctoSense's own apps.` | | 在 App Hub 的 `card-host` 中调用任何服务 | `no service answers "" on this device`(`card-host` 不注册任何服务) | -第一行、`llm` 一行和 `card-host` 一行已于 2026-09-27 在 `card-host`(App Hub `362d832`)中运行验证。回复、参数不合规的返回和缺少内核的返回已于 2026-09-28 在 macOS 上运行验证:release 版桌面端、隐藏窗口,经启动器打开一个声明了 `octos.session.open` 和 `octos.turn.start` 的系统应用;使用按当时锁定的 octos `7bec0918` 构建的内核和用户自己的提供方时,回复来自 peer `card.<应用 id>`,内核数据中出现了它的记忆命名空间 `app/card.<应用 id>/…`。文本长度和开关关闭的返回由 `cargo test -p octosense-ai-host` 覆盖,走的是同一个分发函数。OctoScript-App-Design-Flow 的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 给出了示例应用,以及 Rinx 提供的四个 `octos.*` 调用的参数和返回形状。 +**历史验证(本次未在当前版本重跑)。** 第一行、`llm` 一行和 `card-host` 一行已于 2026-09-27 在 `card-host`(App Hub `362d832`)中运行验证。回复、参数不合规的返回和缺少内核的返回已于 2026-09-28 在 macOS 上运行验证:release 版桌面端、隐藏窗口,经启动器打开一个声明了 `octos.session.open` 和 `octos.turn.start` 的系统应用;使用按当时锁定的 octos `7bec0918` 构建的内核和用户自己的提供方时,回复来自 peer `card.<应用 id>`,内核数据中出现了它的记忆命名空间 `app/card.<应用 id>/…`。文本长度和开关关闭的返回由 `cargo test -p octosense-ai-host` 覆盖,走的是同一个分发函数。OctoScript-App-Design-Flow 的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 给出了示例应用,以及 Rinx 提供的四个 `octos.*` 调用的参数和返回形状。 -manifest 的 `agent` 字段(权限档位、通用工具、迭代和 token 上限)会被 App Hub 接受并按上限裁剪,但 **Shell 中没有任何东西为它运行 Agent**,Rinx 也会拒绝导入声明了它的应用包。应用不能依赖它。 +manifest 的 `agent` 和已准入 `tools.json` 已参与 Shell 的 Agent 发现、工具加载与授权;News/Mail/Calendar 已有宿主服务实现。`profile`/模型需求、`AGENT.md` 提示词、包内 skills 和自动触发器尚未完整消费,`implemented_by: "app"` 没有脚本执行器。Mail 当前只声明 `mail.notify`,不包含 UI 的读信/发信方法;Agent 工作目录不会自动暴露宿主数据库。Rinx 小程序准入是另一套约定,不能默认它支持 App Hub 的所有元数据。 ## 规划中:事件驱动的应用 Agent(ADR 0002) @@ -200,23 +205,25 @@ manifest 的 `agent` 字段(权限档位、通用工具、迭代和 token 上 | 组成部分 | ADR | 状态 | | --- | --- | --- | -| `tools.json`:名为 `.` 的工具,JSON Schema 输入输出,`risk`(`read`、`act`、`destructive`),`confirm`(`host` 或 `app`),`background`、`shareable`、`implemented_by`(`host-service` 或 `app`) | §4、§12 | App Hub 接受并锁定([App-Hub#18](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/18),`crates/app-policy/src/agent.rs`)。目前没有 Shell 加载它。 | -| `AGENT.md`、只含数据的 skills、模型**需求**(从不写提供方或模型名)、`background`、`triggers`(cron、宿主服务事件) | §2、§3 | 同上:App Hub 已接受(`crates/app-policy/src/agent.rs`),Shell 锁定的 App Hub `e8601b80` 已包含这些字段。目前还没有 Shell 运行它们。 | -| 内核:按 peer 由宿主注册工具(`peer/tools/register`、`peer/tool/call`/`result`/`cancel`),强制工具列表和风险等级,审批只在宿主连接上进行,通用工具白名单,`peer/input` | §4、§13 | 进行中:[octos#2567](https://github.com/octos-org/octos/pull/2567)(UPCR-2026-035,草稿)。Shell 一侧是 ADR 0004 计划第 6 步。 | -| 风险决定监督方式:read 和应用内 act 无人值守运行;destructive 等待用户(`confirm: host`:内核的审批路径;`confirm: app`:用户在场时用应用自己的面板,不在场时在应用的对话中生成审批请求) | §4、§12 | 已在 App Hub(#18)和 octos#2567 中声明。Shell 的审批路由、审批面板和常设规则已合入([#120](https://github.com/OctoSense-org/OctoSense/pull/120)),接收 AI 服务总线的 `confirm: host` 调用;内核工具调用要等 octos#2567 合入后才会进入([架构 § 审批](architecture.zh-CN.md#5-审批))。Rinx 的 `send_message` 已经在自己的界面上按 `confirm: app` 的方式工作。 | +| `tools.json`:名称、输入输出 schema、风险、确认、共享和实现 | §4、§12 | `host_tools/script_apps.rs` 已加载、注册到 peer 并转发到宿主服务执行器;News/Mail/Calendar 已声明工具。任意 `implemented_by: "app"` 脚本工具执行仍不可用。 | +| `AGENT.md`、只含数据的 skills、模型需求、`background` 和触发器 | §2、§3 | 已准入的元数据;Shell 尚未实现提示词/skill 加载、按这些需求选模型和触发调度。工具可后台运行不等于会自动启动回合。 | +| 内核:宿主注册工具、风险/列表检查、宿主审批、通用工具白名单和 `peer/input` | §4、§13 | 已实现并在锁定版本中;Shell 注册工具、接收输入、检查 schema/预算并通过 relay 调用执行器。见 `crates/app-peers` 和 `crates/shell/src/host_tools/`。 | +| 风险决定监督方式:read/应用内 act 与 destructive,`confirm: host/app` | §4、§12 | 已实现:AI 服务总线和内核 `host_tool` 审批进入 Shell 路由,其他 peer 内核工具审批也由宿主处理。`confirm: app` 需要注册所属应用面板;Rinx 的总线发送面板不代表已注册到 peer。 | | News M1:`news` 数据服务(不使用模型) | 第一个切片 | 已合入([#69](https://github.com/OctoSense-org/OctoSense/pull/69));issue [#60](https://github.com/OctoSense-org/OctoSense/issues/60)。 | -| News M2:`os.news` 获得 peer,并注册它的工具 | 第一个切片 | 规划中:[#61](https://github.com/OctoSense-org/OctoSense/issues/61)。 | +| News M2:`os.news` peer 及工具 | 第一个切片 | 已实现:manifest `agent`、`news.list`/`news.read`、Shell peer 准备与 relay。 | | News M3:触发器和无人值守运行 | 第一个切片 | 规划中:[#62](https://github.com/OctoSense-org/OctoSense/issues/62)。 | -| News M4:glance 卡片(`glance.publish`、glance 页面和桌面面板) | §7、§8 | `glance.publish`([#72](https://github.com/OctoSense-org/OctoSense/pull/72))和供隔离应用使用的 `glance` 权限([#86](https://github.com/OctoSense-org/OctoSense/pull/86),配合 [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22))已合入;进行中:`sys.digest` 数据源([#87](https://github.com/OctoSense-org/OctoSense/pull/87),草稿);issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63)。 | -| M5:系统工具箱(检索、抓取)作为可授予的工具 | §6 | 规划中:[#64](https://github.com/OctoSense-org/OctoSense/issues/64)。已合入:工作流模板([#82](https://github.com/OctoSense-org/OctoSense/pull/82),`crates/toolbox`)和 octos 的检索引擎([octos#2568](https://github.com/octos-org/octos/pull/2568));进行中:把工具箱提供给应用 Agent([#108](https://github.com/OctoSense-org/OctoSense/pull/108),草稿)。 | +| News M4:glance 卡片(`glance.publish`、glance 页面和桌面面板) | §7、§8 | `glance.publish`([#72](https://github.com/OctoSense-org/OctoSense/pull/72))和供隔离应用使用的 `glance` 权限([#86](https://github.com/OctoSense-org/OctoSense/pull/86),配合 [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22))已合入;`sys.digest` 有单独的运行时/宿主要求;[#87](https://github.com/OctoSense-org/OctoSense/pull/87) 是历史跟踪链接,不表示当前 PR 状态;issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63)。 | +| M5:作为获授权工具的系统工具箱 | §6 | 已在 `toolbox-peers` feature 下实现,见 `crates/ai-host/src/toolbox_peers.rs` 和 Shell 工具箱执行器。Home 默认开启,桌面需显式开启;仍需准入、授权和同意,不是与系统 Agent 的通用对话。 | | M6:渲染与评审(`card-studio`) | §7 | App Hub 的 `card-studio` crate 已合入([App-Hub#19](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/19));对应 skill 规划中([#65](https://github.com/OctoSense-org/OctoSense/issues/65))。 | -| M7:每个应用的对话(审批、提问)、记忆 | §9、§10 | 规划中:[#66](https://github.com/OctoSense-org/OctoSense/issues/66)。Shell 一侧的审批面板和同意已存在([#120](https://github.com/OctoSense-org/OctoSense/pull/120))。 | +| M7:应用对话、问题和记忆 | §9、§10 | 已实现人类/系统通道、Ask-app 面板、`sys.chat`、宿主路由的问题/审批及 peer/context 记忆。见[导读](architecture-walkthrough.zh-CN.md)。 | | M8:外层循环(叠加在 `AGENT.md` 上的 overlay) | §11 | 规划中:[#67](https://github.com/OctoSense-org/OctoSense/issues/67)。 | 跟踪 issue 是 [#68](https://github.com/OctoSense-org/OctoSense/issues/68)。文件格式见 App Hub 的 [PUBLISHING § The app's agent and tools](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/PUBLISHING.md#the-apps-agent-and-tools)。 ## 本地运行与测试 +以下命令**本次文档修正未验证**;架构导读另行记录实际运行的检查。 + ### 桌面端:使用临时的内核与配置 1. 在 [octos-org/octos](https://github.com/octos-org/octos) 的检出中,构建根 `Cargo.toml` 锁定的版本(`ae230ce0`;参数与 `tools/kernel-artifact.py` 相同;本次更新未在此版本上运行,**unverified**): @@ -240,7 +247,7 @@ manifest 的 `agent` 字段(权限档位、通用工具、迭代和 token 上 日志中会出现 `octos: kernel service ready (starts on first use), core dir …`。没有 `OCTOS_APP_CORE_BIN` 时日志会说明没有内核,AI providers 仍会保存提供方。 3. 打开 **Start → Settings → AI providers**,添加一个模型(family、模型、路由、密钥、**Test connection**、保存)。配置文件是 `$T/octos-home/.octos/profiles/_main.json`;使用文件密钥库时密钥就在其中,用完后请删除 `$T`。 -4. 通过某个使用者来使用助手:Rinx(默认链接并在进程内运行;从启动器打开它;登录 Matrix,在首次使用面板上允许它的 Agent,然后使用它的助手),或 AppCard(`--features app-appcard`)。隔离运行的应用通过 `octos` 宿主服务访问它([见上文](#隔离运行的脚本应用系统应用和商店应用));在第 2 步的命令中加上 `OCTOSENSE_CONTAINED_APPS=1`,并在 Shell 询问时允许该应用的 Agent。 +4. 通过某个使用者来使用助手:Rinx(默认链接并在进程内运行;从启动器打开它;登录 Matrix,在首次使用面板上允许它的 Agent,然后使用它的助手),或 AppCard(`--features app-appcard`)。隔离运行的应用通过 `octos` 宿主服务访问它([见上文](#隔离运行的脚本应用系统应用和商店应用));保持 `OCTOSENSE_CONTAINED_APPS` 未设置,并在 Shell 询问时同意。F8 也可打开系统聊天;`agents.ask` 用于同意/准备,`peer_send_input` 才委派任务。 **隐藏窗口。** 加上 `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=`,即可通过远程控制桥操作 Shell 而不占用屏幕([桌面端 README § Remote-control bridge](../desktop/README.md#remote-control-bridge))。`desktop/scripts/ai_providers_remote.sh` 以这种方式端到端运行 AI providers,使用假密钥并禁止出站 HTTPS;`desktop/scripts/glance_remote.sh` 对 glance 面板做同样的事。 @@ -258,7 +265,7 @@ OCTOS_APP_PEERS_TEST_KERNEL=/path/to/octos cargo test -p octosense-app-peers --f ### 手机 -- **Android(Home):** Home APK 把内核打包为 `liboctos.so`;`cd phone && python3 ../rom/scripts/build-home.py` 构建这对 APK(见 [phone/README.md](../phone/README.md)),其中使用 [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) 按锁定的 octos 版本构建内核。内核在首次使用时启动。 +- **Android(Home):** Home APK 把内核打包为 `liboctos.so`;配置好参数的 `rom/scripts/build-home.py` 流水线构建 APK 对(见 [phone/README.md](../phone/README.md)),其中使用 [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) 按锁定的 octos 版本构建内核。内核在首次使用时启动。 - 在 **OctoSense Settings → Accounts → AI providers** 中配置提供方,或者从桌面端迁移:在桌面端点 **Show QR for phone**,然后在手机上通过相机、图片或粘贴代码导入,并输入 PIN。 - **OpenHarmony** 在进程内运行内核。**iOS** 没有内核:提供方会被保存,但没有应用能获得助手。 diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md new file mode 100644 index 00000000..d25c254f --- /dev/null +++ b/docs/architecture-walkthrough.md @@ -0,0 +1,223 @@ +# Code walkthrough: from an app window to an agent turn + +English | [简体中文](architecture-walkthrough.zh-CN.md) + +This is a reading path for a Rust developer who knows structs, traits and functions but is new to OctoSense and agents. It follows OctoSense `c19da8d` and its Cargo-pinned octos `ae230ce0`, inspected on 2026-10-01. The [architecture reference](architecture.md) explains the broader design; this tutorial follows calls and ownership in the implementation. An ADR describes a decision, not proof that all its steps execute today. + +## 1. Give each name one meaning + +| Name | Meaning in this walkthrough | +| --- | --- | +| OctoSense | The desktop/Home shell, apps and their host services. The ROM packages Home with Android platform components. | +| Makepad | Rust UI/event/rendering framework. A widget tree is updated by its event loop. | +| Splash / Makepad Script | The script VM and UI language used by contained `main.splash` apps. This is not the separate Octoscript L0 parser. | +| Octoscript and Octoscript-Makepad | The L0 card language/checker/lowering and its Makepad integration, alongside runtime support for apps. L0 `.card` content and a contained `main.splash` program follow different loading paths. | +| octos | The agent kernel: model calls, turns, tools, transcripts, memory and peer coordination. It is not an operating-system kernel. | +| Agent | A configured model-driven worker: it reads messages, calls available tools, consumes their results and produces an answer. Model output does not itself perform an app operation. | +| Session / turn | A session identifies a conversation and its state. A turn is one execution responding to input; it can include several model requests and tool calls. | +| Peer / request context | A peer is a durable cooperating agent identity. A context is another session belonging to that peer, with its own transcript, workspace and child memory namespace. | +| Tool / host service | A tool is an operation offered to the model. A host service is Rust code called by an app or tool executor. Exposing one API does not automatically expose the other. | +| `AGENTS.md` / `AGENT.md` | Repository contributor instructions / an app-bundle agent-instructions artifact. The bundle artifact is admitted by App Hub, but is not yet loaded into the shell peer's prompt. | + +For the other repositories, continue with [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow), [App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub), [Octoscript-Makepad](https://github.com/OctoSense-org/Octoscript-Makepad) and [octos](https://github.com/octos-org/octos). Their detailed tours are [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/CODE-WALKTHROUGH.md), [App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/CODE-WALKTHROUGH.md), [framework](https://github.com/OctoSense-org/Octoscript-Makepad/blob/main/docs/architecture-walkthrough.md) and [octos integration](https://github.com/octos-org/octos/blob/main/docs/octosense-integration-walkthrough.md) (companion documentation changes must be published before these new links resolve on GitHub). Read each repository's own lock: a nearby checkout's `main` may differ from the revision this shell uses. + +## 2. Start at the executable, then follow the app host + +Open [desktop/src/main.rs](../desktop/src/main.rs), [phone/src/main.rs](../phone/src/main.rs), then [crates/shell/src/lib.rs](../crates/shell/src/lib.rs). Desktop and Home are two packages linking the shared shell. The phone also supplies Settings and platform integration. The ROM does not supply a second Rust agent architecture: it packages Home and privileged Android services. + +The launch choices come from [native-apps.json](../native-apps.json), [AppRegistry in apps.rs](../crates/shell/src/apps.rs) and each packaging's `system-apps.json`: + +| What you launch | Follow the code | What is actually running | +| --- | --- | --- | +| Native Rust module, such as Reference or Rinx | [module_host.rs](../crates/shell/src/module_host.rs): module creation, scoped handles, assistant/storage offers | Rust code and UI in the shell process; each instance gets a script isolate. The isolate does not isolate arbitrary Rust memory. | +| Native process app, currently desktop Terminal where supported | [clients.rs](../crates/shell/src/clients.rs), [hub.rs](../crates/shell/src/hub.rs), [process-apps](../crates/process-apps/src/lib.rs) | A child executable renders frames and exchanges input/AI-bus messages over the authenticated Makepad hub. This is separate from the octos protocol connection. | +| Contained script app | App Hub's `CARD_MODULE`, reached through `apps.rs` | The Card runner admits the bundle and makes a restricted, nested Splash VM; capabilities limit access to host services and platform APIs. No Rust executable is compiled per bundle. | +| L0 glance card | [glance.rs](../crates/shell/src/glance.rs), [glance_chat.rs](../crates/shell/src/glance_chat.rs) | Checked card content lowered/rendered by the runtime, with host-provided data and chat. The card is not another peer. | + +Read the product tutorials for command details: [desktop](../desktop/README.md), [Home](../phone/README.md), [ROM](../rom/README.md), and [system apps](../apps/README.md). A minimal developer route is below. **The launch/build commands in this block are source-checked but unverified in this review; no visible app or device was launched.** Run from this repository root: + +```sh +python3 tools/setup.py --hub /path/to/existing-clones +python3 tools/setup.py --check --cargo +cargo run --release -p octosense +# An opt-in, in-process Rust example: +MAKEPAD_WM_TEST_APP=reference cargo run --release -p octosense --features app-reference -- --module reference +# A shell with the kernel integration; point at a binary built from Cargo.toml's octos rev: +OCTOS_APP_CORE_BIN=/path/to/pinned/octos \ + cargo run --release -p octosense --features octos-core +``` + +The AI providers host-owned sheet must also configure a provider/model before a real conversation can run. A Rust build does not provision those credentials. `OCTOS_APP_CORE_BIN` names a file; this kernel launcher does not search `PATH`. For automated UI work use the existing hidden-window instructions in the product README. + +For a script app, Design Flow's `tools/octo` wraps App Hub's `card-host` and `hub` commands. It is a Python development CLI, unrelated to the octos kernel. `card-host` exercises the contained UI and policy; it does not install the shell's Mail, Calendar, provider or peer services. Use a shell to test those integrations. Do not interpret successful `hub check` as a successful agent turn. + +## 3. Find who owns the kernel + +Read [ai-host/src/lib.rs](../crates/ai-host/src/lib.rs), then [kernel/src/lib.rs](../crates/kernel/src/lib.rs), [launch.rs](../crates/kernel/src/launch.rs), [kernel.rs](../crates/kernel/src/kernel.rs) and [router.rs](../crates/kernel/src/router.rs). + +1. The shell calls `ai_host::start`, registering host services and configuring the kernel source. `model.complete` is a one-shot provider request; it does not create a peer or run a tool loop. +2. The first authorized consumer calls `Core::connect`. It obtains a logical `Connection`; subsequent consumers share the same kernel generation. +3. `launch::resolve` selects a desktop child (`OCTOS_APP_CORE_BIN` or an explicit program), Android's executable packaged as `liboctos.so`, or an embedded OpenHarmony service. iOS has no kernel here. +4. `kernel::supervise` owns the running process/task and frame pump. `Router` correlates consumer request IDs and session events over the one physical protocol connection. +5. The protocol is OUP, JSON-RPC messages and asynchronous notifications. Ordinary mode uses newline-delimited JSON over stdio. Enabling Talk to Octos selects a host-managed loopback WebSocket; it does not start an extra kernel for each client. +6. Provider changes restart the generation. Consumers must reconnect and rebind. Dropping a Rust `Connection` is not deleting the peer's saved memory. + +The privileged Android service in the ROM is a different use of the word “agent”: it performs permitted platform operations through the Android bridge. It does not run the system LLM conversation. + +## 4. Follow a system-chat message + +Open [system_chat/mod.rs](../crates/shell/src/system_chat/mod.rs), [session.rs](../crates/shell/src/system_chat/session.rs), [link.rs](../crates/shell/src/system_chat/link.rs), and [system_tools.rs](../crates/kernel/src/system_tools.rs). + +The assistant pane sends a `Command` to its worker. The `Driver` opens `_main:api:octosense#system`, reads history and starts a turn. Incoming events update a chat model, and `SignalToUI` wakes the Makepad event loop to draw a snapshot. The UI is not awaiting the model on its drawing thread. + +The system agent is a session on the `_main` profile. The host narrows its kernel tools using `session/tool_list/set`; `SYSTEM_AGENT_TOOLS` includes `peer_list`, `peer_send_input`, `peer_gather` and `peer_respond`. Its normal command-execution route, if the person enables it, is the shell's `terminal.run` tool and approval UI. It is not octos's builtin `shell` tool. + +[agents.rs](../crates/shell/src/agents.rs) adds two useful host tools: `agents.list` discovers app agents and their availability; `agents.ask` requests first-use consent. `agents.ask` is not a universal app-to-system chat API, and the model cannot grant consent itself. + +## 5. Prepare one app peer, then give it two lanes + +Read [app-peers/src/contract.rs](../crates/app-peers/src/contract.rs) before the much larger [broker.rs](../crates/app-peers/src/broker.rs). The traits explain the boundary: + +- `OctosAppService`: the scoped assistant handle an app receives. +- `OctosContext`: a conversation/request handle. `call(ContextOp, EventSink)` starts work and delivers `ContextEvent`s. +- `ContextSpec`: host-authenticated account, instance and granted service names. +- `Broker`: the shell's implementation, holding connection, peer, contexts and in-flight requests behind `Arc`. + +A native module receives its handle through [hosted.rs](../crates/app-peers/src/hosted.rs) and [injection.rs](../crates/app-peers/src/injection.rs). A contained app reaches the same broker through [contained.rs](../crates/ai-host/src/contained.rs). A script agent is eligible when its manifest declares assistant services, an `agent` block, or the bundle carries `tools.json`. Eligibility still requires a kernel, consent and an active account where applicable. + +`card.os.news` is the broker's app identity, not necessarily the kernel's generated peer slug. `peer/prepare` returns that slug, the peer session and a host credential; use the returned values. Peers are keyed by app and account. Accountless apps use `device`; Mail uses the host-reported signed-in account. `ensure_peer` resumes the recorded peer, verifies its namespace, and registers tools before a turn can run. + +```mermaid +sequenceDiagram + participant H as Human + participant S as System agent session + participant K as octos + participant B as Shell broker + participant A as App peer session + participant C as App conversation context + S->>K: peer_send_input(peer, task) + K->>B: peer/input notification + B->>B: check account, consent, tool registration; queue input + B->>K: turn/start on peer session, with input id + K->>A: execute system lane turn + H->>B: Ask app: ContextOp::Turn + B->>K: peer/context/open with share_history; turn/start + K->>C: execute human lane turn + A-->>K: completed turn / peer result + K-->>S: blackboard result available to peer_gather + C-->>B: streamed events and completion + B-->>H: app conversation / in-card chat reply +``` + +The app peer session is the **system lane**. `open_conversation` creates a request context with `share_history` for a **human lane**. They have separate transcripts and turn state; bounded recent text from the other lane is supplied read-only. Multiple human surfaces may create separate conversation contexts of the same peer. `open_context` is the non-sharing path for per-client work, such as Rinx mini apps. A request context is its own kernel session, but is not another app peer. + +The broker's `driver_of` and `take_over` handle multiple native instances sharing a peer: one broker drives the system-lane input queue. This prevents every open app window from independently running the same `peer/input`. Human-context work is separate and can run while that queue's current turn is active. + +## 6. Where a person talks, and where the answer goes + +| Surface | Implementation and behavior | +| --- | --- | +| System assistant pane, F8 | `system_chat`: system session; routes app questions raised during system-delegated work here too. | +| “Ask ”, Shift+F8 | [app_chat/mod.rs](../crates/shell/src/app_chat/mod.rs): `agents::conversation`, subscription to both lanes and merged history. Send starts the person's context turn. | +| An app's own native chat | Injected `OctosAppService::open_conversation`; the app renders its events. | +| A script app's own chat | Exact granted `octos.session.open`, `octos.session.history`, `octos.turn.start`, `octos.turn.interrupt` calls through `host.request`. Today's News/Mail/Calendar agents can be shell-driven without their script declaring these calls. | +| A published card's chat | `sys.chat` → [l0-chat](../crates/l0-chat/src/lib.rs) and [glance_chat.rs](../crates/shell/src/glance_chat.rs). Publisher checks bind it to the card's owning app. | + +Phone touch navigation does not yet expose an equivalent control to open the Ask-app panel; app-owned chat and published-card chat are separate surfaces. The Ask-app panel's Stop interrupts the human lane; “Stop the system agent's task” targets the other lane. The lower-level conversation `ContextOp::Interrupt` is broader and can interrupt both: do not assume all Stop surfaces call the same method. Hiding the Ask panel keeps its context/subscription; changing app or revoking access closes it. + +The shell stamps a composer action as `TurnTrigger::Person`. A script can supply `trigger`/`from` with `octos.turn.start`, but its `trigger: "person"` becomes `AppSaysPerson`: a transcript label is not proof of a trusted human gesture and cannot unlock human-initiated approval rules. + +An app agent's structured tool result returns to that app turn, not directly to whichever UI happens to be focused. Final human-context events go back through that context's event sink; a system-delegated turn makes its result available on the peer blackboard for the system agent to gather and summarize. + +## 7. Trace a tool to actual Rust code + +Read [host_tools/script_apps.rs](../crates/shell/src/host_tools/script_apps.rs), [relay.rs](../crates/shell/src/host_tools/relay.rs), and [app-peers/host_tools.rs](../crates/app-peers/src/host_tools.rs). + +For a concrete example, follow Calendar's `calendar.events`: + +1. [tools.json](../apps/calendar/bundle/tools.json) declares its schema, risk, sharing and implementation. App Hub validates/digests the bundle. +2. `script_apps::from_bundle` loads admitted declarations; `install` adds them to the relay catalog and installs a `HostServiceExecutor`. +3. The peer's driving broker registers the exact tool roster with `peer/tools/register`. A model can now request that declared tool. +4. octos emits `peer/tool/call`. The broker stamps the actual caller/account/context and passes it to the shell's `ToolHost`. +5. `Relay::handle` checks authorization, consent, account state, input schema, size and call budgets. Required approvals are resolved through the shell. +6. The executor invokes the Calendar host service as the **owning app**, which reads [Calendar's store](../apps/calendar/host-service/src/lib.rs). The reply queue returns the outcome; output schema/size are checked and `ToolReply` sends at most one `peer/tool/result`. +7. The model consumes that JSON result and continues its turn. It may answer in text or call another granted tool. + +The declaration is not the implementation. `implemented_by: "host-service"` works only where the service exists and the owner may call it. `implemented_by: "app"` is admitted metadata, but the Card runner's script executor is not implemented; it returns unavailable. Neither a copied `tools.json` nor a successful gate check creates missing service code. + +## 8. What “access the app's data” actually means + +There are several stores, with separate ownership: + +| Data | How an app agent reaches it | +| --- | --- | +| App account folder | [app_storage](../crates/shell/src/app_storage/mod.rs) and `ToolHost::agent_workspace` bind a new peer's cwd to the permitted folder. Kernel file tools still need grants. | +| Account text files from a request context | [files.rs](../crates/shell/src/host_tools/files.rs): shell-owned `files.list/read/search`, currently Unix only, only with consent and an available workspace. They are bounded, reject symlink traversal and hide sibling contexts. They are not SQLite query APIs. | +| Human conversation's parent account folder | `read_parent` is requested only where `storage.agent_workspace: "account"` allows it. Parent is read-only; context writes stay in its own folder. Plain client contexts do not get this automatically. | +| Host-service database or remote account | A specific declared tool, implemented by the owning host service. Workspace access does not mount every host database or grant remote credentials. | +| Agent transcript and memory | octos session/context and `app//acct-` namespaces. These are separate from the app's business data. | +| Secrets | Host-owned secret store/sheets; not the agent workspace or script state. | + +For example, Calendar keeps `calendar/events.json` under its host directory and exposes operations through `calendar.*`. News exposes `news.list` and `news.read`. Mail's current agent declaration exposes **only `mail.notify`**; the Mail UI's ability to list messages or send mail does not mean the model has those tools. The older AppCard personal-data importer is not automatically synchronized with current Mail's store. + +Account directory names use a SHA-256-derived tag; peer memory names use the broker's FNV-derived tag. These are compatibility identifiers, not interchangeable paths. Sign-out suspends access and retains data; account removal/uninstall additionally requests `peer/purge`, retrying busy peers. A peer's saved workspace cannot silently change on resume. + +## 9. Cross-app work and asking for help + +Three operations are easy to confuse: + +**Delegation:** the system agent uses `peer_send_input` to ask an existing app peer to do work, then gathers its answer. The shell remains responsible for driving that app turn. The peer is not a newly spawned process. + +**Calling another app's API as a tool:** `Catalog::owner_of` resolves an owner; `may_call` requires an existing declaration plus `shareable: true` and a grant for that caller (outside explicit developer-mode rules). Script manifests request dotted names through `agent.tools`; native entries use their reviewed grants. Admission is a separate prerequisite: App Hub `HostLimits.offered_tools` must offer a requested name; its default does not offer arbitrary names such as `mail.send`. A relay implementation does not override that gate. The relay calls the owner's executor without having to ask the owner's model. The receiving app's data remains behind that executor. Current owner resolution covers native namespaces, toolbox namespaces and `os.`; it is not an arbitrary installed-store-app discovery mechanism. + +**A question or system facility:** an app agent can call a granted `ask_user_question`. [questions/mod.rs](../crates/shell/src/questions/mod.rs) routes it according to the initiating turn: system chat for a system-delegated turn, app conversation for a human/app turn. A person answers on a shell surface. This is not a way for a script to obtain system-agent privileges. octos has peer-supervision mechanisms, but the shell does not give every contained app a general `ask_system_agent` API or unrestricted peer tools. Likewise the [system toolbox](../crates/toolbox/README.md) supplies granted Rust tools/workflows; calling it is not talking to the system-agent conversation. + +The system agent's `peer_respond` capability is not permission to approve an app's action for the person. Tool approvals and human questions have distinct protocol messages and host-owned answer handles. Prompt deadlines deny/decline unanswered prompts; they never turn silence into consent. + +## 10. Map the architecture to Rust execution + +An `async fn` returns a future; polling it advances work until it must wait. A Tokio task is a scheduled future. An OS thread runs many task polls. A persisted session or peer can outlive every task currently handling it. + +| Layer | Actual execution model | Source | +| --- | --- | --- | +| Makepad shell | UI event loop; widget drawing, event dispatch and host-tool relay pump | `module_host.rs`, `host_tools/mod.rs` | +| System chat | An ordinary `std::thread`; commands and snapshots; `link::poll_for` uses a waker/unpark to poll kernel receive | `system_chat/mod.rs`, `link.rs` | +| Shell kernel service | Lazily built Tokio runtime: **2 worker threads**, **8 MiB stacks**. One generation supervisor task owns transport and process lifecycle, with auxiliary I/O tasks | `kernel/src/lib.rs::Inner::runtime`, `kernel.rs::supervise` | +| App broker | **Each `Broker::new` builds a runtime with 1 worker thread**. Link pump, request futures, retries and deadline tasks run there. Multiple brokers may share one durable peer | `app-peers/src/broker.rs` | +| Embedded OpenHarmony kernel | `serve_io` is spawned on the host runtime over `tokio::io::duplex`; no child executable | `kernel.rs::start` | +| octos OUP turn | Active-turn admission precedes a spawned `run_standalone_turn`; its agent/model processing and progress/heartbeat use further tasks | pinned octos `crates/octos-cli/src/api/ui_protocol_transport.rs` | +| octos transport output | WebSocket has an async writer task; embedded/stdio uses a bounded synchronous queue and an ordinary writer thread. Transport variants are not identical | same octos file | +| Host service / file executor | Depends on the service: UI pump, callback/reply queues, worker threads for blocking operations. Not universally a Tokio task per service or app | `host_tools/files.rs`, App Hub `services.rs`, app host services | + +```mermaid +flowchart LR + UI["Makepad UI thread"] --> CMD["System-chat std thread"] + UI --> B["Broker runtime(s): request and link tasks"] + CMD --> C["Kernel Connection channels"] + B --> C + C --> SUP["Kernel-service supervisor task"] + SUP <-->|"stdio or host WebSocket"| OUP["octos protocol dispatcher"] + OUP --> T1["System-lane turn task"] + OUP --> T2["Human-context turn task"] + T1 --> TOOL["tool future waits for host reply"] + TOOL --> B + B --> Q["Shell relay queue"] + Q --> UI +``` + +Read `mpsc` as a many-sender mailbox, `oneshot` as one correlated answer, and `watch` as the latest lifecycle/readiness state. In the broker, request IDs map replies to `oneshot` senders; its link loop uses `tokio::select!` for outbound and inbound traffic. The kernel supervisor selects control messages, kernel output and process exit. `Arc` shares ownership, `Weak` avoids keeping a dropped broker/context alive, and generation/epoch checks reject replies from an obsolete account or connection. + +The broker's synchronous `bind`/`host_request` wrappers wait for channel replies: do not call such blocking interfaces from a rendering callback. Async model I/O can overlap across sessions; synchronous filesystem work still needs the existing worker boundary. “One peer per app/account” is an identity and isolation rule, **not one Tokio task or thread per agent**. + +## 11. Verify one boundary at a time + +These checks were run for this documentation review: + +- Runtime setup with the existing clone hub, followed by `python3 tools/setup.py --check --cargo`: passed. +- `python3 tools/native_apps.py --check` and `python3 -m unittest discover -s rom/tests -p test_no_local_paths.py`: passed. +- Changed Markdown relative-file links and `git diff --check` across the five documentation worktrees: passed. +- `cargo test --locked -p octosense-kernel -p octosense-app-peers --features octosense-app-peers/octos-core,octosense-app-peers/ws`: passed the unit and scripted-connector suites. Real-kernel test functions early-return unless their binary environment variables are supplied; this review did not supply them and does **not** claim those integrations passed. + +Use [broker tests](../crates/app-peers/tests/broker.rs) as executable examples: `a_persons_message_runs_while_the_system_agents_input_runs`, `a_lane_stop_leaves_the_other_lane_running`, `a_kernel_without_shared_history_is_refused_for_the_conversation`, and `removing_an_account_purges_its_recorded_peer_and_drops_the_record`. They demonstrate actual protocol behavior without a paid model. [Shell relay scenario tests](../crates/shell/src/host_tools/scenario_tests.rs) show caller/tool/approval boundaries; they were read, not executed in this review. + +Desktop GUI launch, real-provider turns, Android/OpenHarmony/iOS builds, ROM image builds and flashing are **unverified in this review**. `AGENT.md` prompt loading, automatic bundle triggers/skills, arbitrary script-implemented agent tools and a general app-to-system-agent RPC remain implementation gaps. Do not turn an architectural example into a claimed working workflow without checking its declarations and executor. diff --git a/docs/architecture-walkthrough.zh-CN.md b/docs/architecture-walkthrough.zh-CN.md new file mode 100644 index 00000000..ac80a9d8 --- /dev/null +++ b/docs/architecture-walkthrough.zh-CN.md @@ -0,0 +1,169 @@ +# 代码导读:从应用窗口到 Agent 回合 + +[English](architecture-walkthrough.md) | 简体中文 + +本文面向了解 Rust 结构体、trait 和函数,但不熟悉 Agent 与 OctoSense 的开发者。阅读依据是 2026-10-01 检查的 OctoSense `c19da8d`,以及 Cargo 锁定的 octos `ae230ce0`。[架构参考](architecture.zh-CN.md)说明整体设计;本文沿着调用链、数据所有权与执行边界阅读实现。ADR 中的决定不代表所有步骤都已运行。 + +## 1. 先区分名字 + +| 名称 | 在这里的含义 | +| --- | --- | +| OctoSense | 桌面/Home Shell、应用和宿主服务;ROM 将 Home 与 Android 平台组件一起打包。 | +| Makepad | Rust UI、事件循环与渲染框架。 | +| Splash / Makepad Script | 受限 `main.splash` 应用使用的脚本 VM 和 UI 语言,不是独立的 Octoscript L0 解析器。 | +| Octoscript / Octoscript-Makepad | L0 卡片语言、检查/降级到运行时的工具和 Makepad 集成;`.card` 与 `main.splash` 的加载路径不同。 | +| octos | 负责模型调用、回合、工具、记录、记忆及 peer 协作的 Agent 内核,不是操作系统内核。 | +| Agent | 读取消息、选择已提供的工具、根据结果继续推理并回答的模型工作单元。模型输出本身不会执行应用操作。 | +| session / turn | session 标识会话及其状态;turn 是一次输入引起的执行,可包含多次模型和工具调用。 | +| peer / request context | peer 是持久协作身份;context 是该 peer 下的另一个会话,有独立记录、工作目录和子记忆命名空间。 | +| tool / host service | tool 是提供给模型的操作;host service 是处理应用或工具执行器请求的 Rust 实现。两者不会自动互相暴露。 | +| `AGENTS.md` / `AGENT.md` | 仓库贡献者规则 / 应用包的 Agent 指令文件。App Hub 可以校验后者,但 Shell 尚未将它装入 peer 提示词。 | + +相关仓库是 [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow)、[App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub)、[Octoscript-Makepad](https://github.com/OctoSense-org/Octoscript-Makepad) 和 [octos](https://github.com/octos-org/octos)。分别读取各自的锁定版本,不要默认相邻 checkout 的 `main` 就是 Shell 使用的版本。 + +## 2. 从可执行入口找到应用宿主 + +先读 [desktop/src/main.rs](../desktop/src/main.rs)、[phone/src/main.rs](../phone/src/main.rs),再读 [shell/src/lib.rs](../crates/shell/src/lib.rs)。Desktop 和 Home 是链接同一 Shell 的两个包;Home 还提供 Settings 与平台集成。ROM 打包 Home 和 Android 特权组件,并未另写一套 Rust Agent 架构。 + +应用启动选择来自 [native-apps.json](../native-apps.json)、[apps.rs](../crates/shell/src/apps.rs) 中的 `AppRegistry`,以及各产品的 `system-apps.json`: + +| 应用形态 | 源码入口 | 实际执行方式 | +| --- | --- | --- | +| Rust 模块,如 Reference、Rinx | [module_host.rs](../crates/shell/src/module_host.rs) | 与 Shell 同进程;每个实例有脚本 isolate,但 Rust 内存仍共享。 | +| 原生进程应用,目前为受支持桌面上的 Terminal | [clients.rs](../crates/shell/src/clients.rs)、[hub.rs](../crates/shell/src/hub.rs)、[process-apps](../crates/process-apps/src/lib.rs) | 子进程通过经过认证的 Makepad hub 交换帧、输入和 AI-bus 消息。此连接不同于 octos 协议连接。 | +| 受限脚本应用 | App Hub 的 `CARD_MODULE`,从 `apps.rs` 接入 | 校验应用包后创建嵌套的受限 Splash VM;每个包不需要编译一个 Rust 可执行文件。 | +| L0 glance 卡片 | [glance.rs](../crates/shell/src/glance.rs)、[glance_chat.rs](../crates/shell/src/glance_chat.rs) | 运行时检查、转换并渲染卡片,宿主提供数据和聊天;卡片本身不是新 peer。 | + +具体命令见[桌面](../desktop/README.zh-CN.md)、[Home](../phone/README.zh-CN.md)、[ROM](../rom/README.zh-CN.md)及[系统应用](../apps/README.zh-CN.md)。下面从仓库根目录运行的启动/构建命令已核对源码,但**本次未验证实际启动、GUI 或设备构建**: + +```sh +python3 tools/setup.py --hub /path/to/existing-clones +python3 tools/setup.py --check --cargo +cargo run --release -p octosense +MAKEPAD_WM_TEST_APP=reference cargo run --release -p octosense --features app-reference -- --module reference +OCTOS_APP_CORE_BIN=/path/to/pinned/octos \ + cargo run --release -p octosense --features octos-core +``` + +内核二进制应来自 `Cargo.toml` 锁定的 octos 版本,`OCTOS_APP_CORE_BIN` 必须指向文件;这里不会查找 `PATH`。真实对话还要求用户在宿主拥有的 AI providers 面板配置提供方和模型。编译 Rust 不会自动配置凭据。自动化 UI 检查使用产品 README 的隐藏窗口方式。 + +脚本应用的 Design Flow `tools/octo` 是 Python CLI,包装 App Hub 的 `card-host` 和 `hub`,与 octos Agent 内核无关。`card-host` 可检查受限 UI/策略,但没有安装 Shell 的 Mail、Calendar、提供方或 peer 服务。这些集成必须在 Shell 中验证;`hub check` 通过不代表 Agent 回合成功。 + +## 3. 谁拥有内核 + +阅读 [ai-host/src/lib.rs](../crates/ai-host/src/lib.rs),然后读 [kernel/src/lib.rs](../crates/kernel/src/lib.rs)、[launch.rs](../crates/kernel/src/launch.rs)、[kernel.rs](../crates/kernel/src/kernel.rs) 和 [router.rs](../crates/kernel/src/router.rs)。 + +1. Shell 调用 `ai_host::start` 注册服务、配置内核来源。`model.complete` 是单次模型请求,不会创建 peer 或工具循环。 +2. 首个获准使用内核的消费者调用 `Core::connect`,得到逻辑 `Connection`;后续消费者共享同一代内核。 +3. `launch::resolve` 选择桌面子进程、Android 包装为 `liboctos.so` 的可执行文件,或 OpenHarmony 内嵌服务;iOS 此处没有内核。 +4. `kernel::supervise` 拥有运行中的进程/任务和消息泵;`Router` 在唯一物理连接上关联消费者请求 ID 与会话事件。 +5. OUP 使用 JSON-RPC 请求和异步通知。默认通过 stdio 传输逐行 JSON;开启 Talk to Octos 后改用宿主管理的本地 WebSocket,不会为每个客户端另起一个内核。 +6. 提供方变更会重启内核代次,消费者必须重连、重新绑定。丢弃一个 Rust `Connection` 不等于删除 peer 记忆。 + +ROM 的 Android 特权“agent”执行经过允许的平台操作,不运行系统 LLM 会话。这两个“agent”必须分清。 + +## 4. 跟随系统聊天的一条消息 + +读 [system_chat/mod.rs](../crates/shell/src/system_chat/mod.rs)、[session.rs](../crates/shell/src/system_chat/session.rs)、[link.rs](../crates/shell/src/system_chat/link.rs) 和 [system_tools.rs](../crates/kernel/src/system_tools.rs)。 + +助手面板发送 `Command` 给工作线程;`Driver` 打开 `_main:api:octosense#system`、读取历史并启动回合。事件更新聊天模型,`SignalToUI` 唤醒 Makepad 绘制快照。绘制线程不会同步等待模型完成。 + +系统 Agent 是 `_main` profile 下的会话。宿主通过 `session/tool_list/set` 缩小其内核工具集;`SYSTEM_AGENT_TOOLS` 包括 `peer_list`、`peer_send_input`、`peer_gather`、`peer_respond`。用户开启命令执行后,正常路径是 Shell 的 `terminal.run` 及其审批界面,而不是 octos 内置 `shell`。 + +[agents.rs](../crates/shell/src/agents.rs) 的 `agents.list` 发现应用 Agent 及其状态,`agents.ask` 请求首次同意。后者不是通用的“应用调用系统 Agent”聊天 API,模型也不能替用户同意。 + +## 5. 一个应用 peer,两条并行通道 + +先读 [contract.rs](../crates/app-peers/src/contract.rs),再读 [broker.rs](../crates/app-peers/src/broker.rs):`OctosAppService` 是应用拿到的受限助手句柄;`OctosContext` 是对话/请求句柄;`ContextSpec` 携带宿主认证的账号、实例和服务授权;`Broker(Arc)` 实现连接、peer、context 与在途请求管理。 + +原生模块经 [hosted.rs](../crates/app-peers/src/hosted.rs) 和 [injection.rs](../crates/app-peers/src/injection.rs) 获得服务。脚本应用经 [contained.rs](../crates/ai-host/src/contained.rs) 接入同一 broker。manifest 的助手服务、`agent` 块或 `tools.json` 使应用具备 Agent 资格,但仍需内核、同意及有效账号。 + +`card.os.news` 是 broker 使用的应用身份,不一定是内核生成的 peer slug。`peer/prepare` 返回 slug、会话和宿主凭据,应使用返回值。peer 按应用与账号区分;无账号应用使用 `device`,Mail 使用宿主报告的已登录账号。`ensure_peer` 恢复记录、核验命名空间并注册工具,成功后才执行回合。 + +系统 Agent 调用 `peer_send_input` → octos 发出 `peer/input` → Shell broker 校验和排队 → broker 以 input ID 在 peer 会话调用 `turn/start`。因此是 Shell 驱动应用回合,并非内核收到消息就绕过 Shell 执行。 + +人类通过 `open_conversation` 打开带 `share_history` 的 request context,形成另一条通道。两条通道的 transcript 和回合状态独立;模型只读地看到另一条通道的有限近期文本。多个聊天界面可以打开同一 peer 的不同 conversation context。普通 `open_context` 用于 Rinx mini app 等客户端工作,不共享历史。context 有自己的内核会话,但不是另一个应用 peer。 + +`driver_of` 与 `take_over` 保证一个 peer 的系统输入队列只有一个 broker 驱动,避免每个应用窗口重复执行同一 `peer/input`。人类 context 的回合可以同时运行。 + +## 6. 人在哪里说话,回答回到哪里 + +| 入口 | 实现 | +| --- | --- | +| 系统助手面板 / F8 | `system_chat` 使用系统会话;系统委派任务引发的应用问题也显示在此。 | +| “Ask ” / Shift+F8 | [app_chat](../crates/shell/src/app_chat/mod.rs) 调用 `agents::conversation`,订阅两条通道并合并历史;Send 在人类 context 启动回合。 | +| 原生应用自己的聊天 | 注入的 `OctosAppService::open_conversation`,应用渲染事件。 | +| 脚本应用自己的聊天 | 通过 `host.request` 调用精确授权的四个 `octos.*` 服务。News/Mail/Calendar 自身未声明这些调用,但 Shell 仍可驱动其 Agent。 | +| 卡片中的聊天 | `sys.chat` → [l0-chat](../crates/l0-chat/src/lib.rs) 与 [glance_chat.rs](../crates/shell/src/glance_chat.rs),校验发布者后绑定拥有该卡片的应用。 | + +目前手机触摸导航还没有打开 Ask 面板的对应入口;应用自己的聊天或已发布卡片的聊天是不同入口。Ask 面板的 Stop 只停人类通道;另一个明确的按钮停系统任务。底层 conversation 的 `ContextOp::Interrupt` 范围更大,可中断两条通道,不能把所有 Stop 混为一谈。隐藏面板保留 context/订阅;切换应用或撤销权限才关闭。 + +Shell 将自己的输入动作标为 `TurnTrigger::Person`;脚本 `octos.turn.start` 可携带 `trigger`/`from`,但其 `trigger: "person"` 只成为 `AppSaysPerson`。聊天中的人物标签不证明宿主看到了真实用户操作,也不会解锁仅限用户主动发起的审批规则。 + +工具结果先回到发起它的应用回合,供模型继续处理。人类 context 的最终事件通过其 event sink 回到聊天界面;系统委派回合的结果进入 peer blackboard,系统 Agent 用 `peer_gather` 获取并向用户总结。 + +## 7. 将工具声明追到真正的 Rust 实现 + +读 [script_apps.rs](../crates/shell/src/host_tools/script_apps.rs)、[relay.rs](../crates/shell/src/host_tools/relay.rs) 和 [host_tools.rs](../crates/app-peers/src/host_tools.rs)。以 Calendar 的 `calendar.events` 为例: + +1. [tools.json](../apps/calendar/bundle/tools.json) 声明 schema、风险、共享及实现方式;App Hub 校验摘要和规则。 +2. `from_bundle` 读取已准入声明;`install` 安装 catalog 项和 `HostServiceExecutor`。 +3. 驱动 peer 的 broker 经 `peer/tools/register` 注册精确工具集。 +4. 模型请求调用后,octos 发出 `peer/tool/call`;broker 附上真实调用者、账号、context 并交给 Shell `ToolHost`。 +5. `Relay::handle` 检查授权、同意、账号状态、输入 schema、大小及预算,需要时走 Shell 审批。 +6. 执行器以工具所属应用身份调用 [Calendar 服务](../apps/calendar/host-service/src/lib.rs)。回复经队列回来,输出也经过校验,`ToolReply` 最多发送一次 `peer/tool/result`。 +7. 模型读取 JSON 结果,回答或继续调用其他已授权工具。 + +声明不等于实现。`implemented_by: "host-service"` 需要存在对应服务且所属应用有权限;`implemented_by: "app"` 目前虽能准入,Card runner 尚未实现其脚本执行器,会返回不可用。复制 `tools.json` 或 gate 通过都不会补齐服务代码。 + +## 8. “读取应用数据”有几种完全不同的含义 + +| 数据 | 访问方式 | +| --- | --- | +| 应用账号目录 | [app_storage](../crates/shell/src/app_storage/mod.rs) 和 `agent_workspace` 将新 peer 的 cwd 绑定到获准目录;内核文件工具仍需授权。 | +| context 读取账号文本文件 | Shell 的 [files.list/read/search](../crates/shell/src/host_tools/files.rs),目前仅 Unix、需同意和可用 workspace;有读取上限,拒绝符号链接并隐藏兄弟 context。这不是 SQLite 查询 API。 | +| 人类对话读取父账号目录 | `storage.agent_workspace: "account"` 时请求 `read_parent`,父目录只读、写入仍限自身 context;普通客户端 context 不自动拥有此能力。 | +| 宿主服务数据库或远端账号 | 必须经声明且实现的工具访问;workspace 不会挂载所有服务数据库或泄露凭据。 | +| 对话历史和 Agent 记忆 | octos session/context 及 `app//acct-`,不同于应用业务数据。 | +| 机密 | 宿主的 secret store 和输入面板,不在脚本状态或 Agent workspace。 | + +Calendar 服务在其宿主目录保存 `calendar/events.json` 并通过工具操作;News 暴露 `news.list/read`。Mail 当前 Agent **只声明 `mail.notify`**:Mail UI 能读信和发信不表示模型也能调用。旧 AppCard personal-data 导入器不会自动同步今天 Mail 的存储。 + +账号目录的 SHA-256 标签与 peer 记忆的 FNV 标签是不同的兼容标识,不能互换。登出暂停访问并保留数据;删除账号/卸载还请求 `peer/purge`,遇到忙 peer 会重试。恢复已有 peer 时不能静默更换已记录的 workspace。 + +## 9. 跨应用调用与请求帮助 + +**委派**:系统 Agent 用 `peer_send_input` 请求已有应用 peer 做事,再获取结果;Shell 驱动该回合,并未新建一个进程。 + +**直接调用另一个应用的工具**:`Catalog::owner_of` 解析 owner;`may_call` 要求工具确实存在、`shareable: true` 以及该调用者的授权(显式开发模式另有规则)。脚本 `agent.tools` 中带点名称和原生清单 grants 表达请求;relay 调用 owner 执行器,不一定经过 owner 的模型。当前 owner 解析覆盖原生、工具箱和 `os.`,不是任意商店应用发现机制。还必须通过 App Hub 的 `HostLimits.offered_tools` 准入;默认不提供的 `mail.send` 等名字不能仅靠写入 manifest 获准。 + +**问题或系统设施**:应用 Agent 只有获得 `ask_user_question` 才能使用它。[questions/mod.rs](../crates/shell/src/questions/mod.rs) 按回合来源将问题放到系统聊天或应用聊天,最终由人在 Shell 界面回答。此路由不是获取系统 Agent 权限的方法。Shell 没有给每个受限应用通用 `ask_system_agent` API 或任意 peer 工具。[系统工具箱](../crates/toolbox/README.md) 是工具/工作流服务,调用它也不等于与系统 Agent 聊天。 + +系统 Agent 的 `peer_respond` 不能代替用户批准应用操作。审批与问题使用不同协议消息和宿主句柄;超时只会拒绝/谢绝,不会把沉默当成同意。 + +## 10. 映射到 Rust、线程和 Tokio + +`async fn` 返回 future;poll 推进执行,直到等待 I/O。Tokio task 是被调度的 future,一个 OS 线程可以轮流 poll 很多 task。持久 session/peer 可以比当前处理它的所有 task 活得更久。 + +| 层 | 实际执行方式 | 源码 | +| --- | --- | --- | +| Makepad Shell | UI 事件循环,绘制、模块事件和 relay pump | `module_host.rs`、`host_tools/mod.rs` | +| 系统聊天 | 普通 `std::thread`;命令/快照,通过 waker/unpark 轮询接收 | `system_chat/mod.rs`、`link.rs` | +| Shell 内核服务 | 懒创建 Tokio runtime,**2 个 worker、8 MiB 栈**;一代 supervisor 拥有传输与生命周期 | `kernel/src/lib.rs`、`kernel.rs` | +| 应用 broker | **每次 `Broker::new` 创建 1-worker runtime**;连接、请求、重试与期限任务;多个 broker 可共享同一 peer | `app-peers/src/broker.rs` | +| OpenHarmony 内嵌内核 | 宿主 runtime 上 spawn `serve_io`,通过 `tokio::io::duplex` 通信 | `kernel.rs::start` | +| octos OUP 回合 | 准入后 spawn `run_standalone_turn`,内部模型处理和进度/心跳还有其他任务 | octos `crates/octos-cli/src/api/ui_protocol_transport.rs` | +| octos 输出 | WebSocket 为异步 writer task;stdio/内嵌为有界同步队列和普通 writer 线程 | 同上 | +| 宿主服务/文件执行器 | 随服务而异:UI pump、回调、回复队列、阻塞工作线程;不是统一每应用一个 Tokio task | `files.rs`、App Hub `services.rs`、各服务 | + +`mpsc` 是多发送者邮箱,`oneshot` 是一次对应回复,`watch` 是最新生命周期/就绪状态。broker 用请求 ID 找到 `oneshot`,其连接循环用 `select!` 接收双向消息;supervisor 同时等待控制消息、内核输出与退出。`Arc` 共享所有权,`Weak` 避免让已关闭对象永久存活,generation/epoch 丢弃旧账号或旧连接的迟到回复。 + +同步 `bind`/`host_request` 会等待 channel,不能在绘制回调中阻塞调用。模型异步 I/O 可以并发,阻塞文件操作仍需要现有工作线程边界。**一个应用/账号一个 peer 是身份与隔离规则,不是一个 Agent 对应一个 Tokio task 或 OS 线程。** + +## 11. 本次验证与读代码练习 + +已运行并通过:使用现有 clone hub 的 setup,以及 `python3 tools/setup.py --check --cargo`;`python3 tools/native_apps.py --check`;`python3 -m unittest discover -s rom/tests -p test_no_local_paths.py`;五个文档 worktree 的相对文件链接和 `git diff --check`。另外,`cargo test --locked -p octosense-kernel -p octosense-app-peers --features octosense-app-peers/octos-core,octosense-app-peers/ws` 的单元与脚本化连接测试也通过。真实内核测试未提供所需二进制环境变量,会提前返回,**不算真实内核集成验证**。 + +[broker 测试](../crates/app-peers/tests/broker.rs)可作为逐步练习:阅读 `a_persons_message_runs_while_the_system_agents_input_runs`、`a_lane_stop_leaves_the_other_lane_running`、`a_kernel_without_shared_history_is_refused_for_the_conversation` 和 `removing_an_account_purges_its_recorded_peer_and_drops_the_record`。它们不需要付费模型即可展示协议行为。[relay 场景测试](../crates/shell/src/host_tools/scenario_tests.rs)展示调用者和审批边界;本次仅阅读,未运行。 + +桌面 GUI、真实提供方回合、Android/OpenHarmony/iOS 构建、ROM 构建及刷机均**未验证**。`AGENT.md` 提示词加载、应用包自动技能/触发器、任意脚本实现的 Agent 工具及通用应用到系统 Agent RPC 仍有实现缺口。一个架构示例是否能实际执行,要同时检查声明、授权和执行器。 diff --git a/docs/architecture.md b/docs/architecture.md index 29c1c3ed..75e8a13f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -2,7 +2,7 @@ English | [简体中文](architecture.zh-CN.md) -How OctoSense fits together: which processes run on each platform, where the agents live, how the pieces talk, how tools are granted and approved, where data and secrets are kept, and where the trust boundaries are. It describes `main` on 2026-09-28 (OctoSense `ff40e9c`, which pins octos `5e7577f0`), read in the code. +How OctoSense fits together: which processes run on each platform, where the agents live, how the pieces talk, how tools are granted and approved, where data and secrets are kept, and where the trust boundaries are. The current code-reading companion is the [junior-Rust walkthrough](architecture-walkthrough.md), checked against OctoSense `c19da8d` and its octos `ae230ce0` pin on 2026-10-01. This reference retains dated design/review history; the corrections below reflect that snapshot. Every statement carries its status: @@ -160,7 +160,7 @@ flowchart TB ## 2. Agents -**One kernel per shell; agents are sessions, not processes.** Inside the one kernel, every agent is an octos session run as tokio tasks. Tools such as file edits run in the kernel; octos's command tools run as short child processes in the session's workspace (OctoSense denies them to the system agent, [section 4](#4-tools-and-grants)). +**One kernel per shell; agents are sessions, not processes.** Inside the one kernel, agent turns run as Tokio tasks, while peers and sessions are durable state. A peer can have multiple context sessions and a turn can create several tasks; there is no one-agent/one-task mapping. See the [thread and task table](architecture-walkthrough.md#10-map-the-architecture-to-rust-execution). Tools such as file edits run in the kernel; octos's command tools run as short child processes in the session's workspace (OctoSense denies them to the system agent, [section 4](#4-tools-and-grants)). | Agent | What it is | Status | | --- | --- | --- | @@ -178,7 +178,7 @@ Each app peer has, separately from every other: Who gets a peer today (`crates/ai-host/src/lib.rs`, `Policy::shipped()`; `crates/app-peers/src/hosted.rs`, `effective_services` = declared ∩ supported ∩ policy): - **Rinx**, the only native app granted the assistant (the four `octos.*` services, from its `native-apps.json` `agent.octos`, generated into `crates/ai-host/src/native_agents.rs`), after first-use consent. -- **Script apps with an agent**: a manifest that declares `octos.*` or an `agent` block, or a bundle that ships `tools.json` (News). One peer `card.` each, account `device` (`crates/ai-host/src/contained.rs`, [#106](https://github.com/OctoSense-org/OctoSense/pull/106)), once the person allowed it at first use (the shipped gate; `OCTOSENSE_CONTAINED_APPS=1` asks nobody, `0` turns it off). The shell prepares it as soon as it is allowed, and at startup (`crates/shell/src/agents.rs`, `contained::prepare`), so the system agent's `peer_list` shows it even when the app never calls `octos`; the app's own `host.request("octos.*")` stays limited to what its manifest declares. +- **Script apps with an agent**: a manifest that declares `octos.*` or an `agent` block, or a bundle that ships `tools.json` (News). One peer per app/account with broker identity `card.`, using `device` for accountless apps or the host-reported active account (Mail requires sign-in) (`crates/ai-host/src/contained.rs`, [#106](https://github.com/OctoSense-org/OctoSense/pull/106)), once the person allowed it at first use (the shipped gate; `OCTOSENSE_CONTAINED_APPS=1` asks nobody, `0` turns it off). The shell prepares it as soon as it is allowed, and at startup (`crates/shell/src/agents.rs`, `contained::prepare`), so the system agent's `peer_list` shows it even when the app never calls `octos`; the app's own `host.request("octos.*")` stays limited to what its manifest declares. - **AppCard** (opt-in) takes its own kernel connection and sessions, not a peer. - **Process apps** whose `native-apps.json` entry grants `agent.octos` services reach their peer through the **peer link** (`crates/shell/src/peer_link/`, [#130](https://github.com/OctoSense-org/OctoSense/pull/130)), after first-use consent. None does yet: the Terminal, the only process app, grants none. @@ -246,7 +246,7 @@ For a host-owned peer, a plain `peer_send_input` runs as a kernel continuation w | --- | --- | --- | | In-process native module, through the peer link | Makepad's `OctosPeer::open` parks a channel pair; the module host claims it for the instance whose code opened it and the shell serves it with the process apps' **peer link** (`peer_link::module_connected`, `octosense_ai_host::module_peer`), so the app does not know how it is hosted | On main ([#142](https://github.com/OctoSense-org/OctoSense/issues/142)); no module uses it yet | | In-process native module (Rinx) | the **injected service**: `ai_host::offer` before `create`, `octosense_app_peers::injection::claim` inside it, giving a scoped `OctosAppService` (`Open`, `History`, `Turn`, `Interrupt`, `Approval`); the module never sees the protocol | On main | -| Script app | `host.request("octos.session.open" / "octos.session.history" / "octos.turn.start" / "octos.turn.interrupt", …)` to the `octos` host service (`crates/ai-host/src/contained.rs`); gated by the manifest, `Policy::contained_apps` and first-use consent (`consent_for_contained`); tool approvals its peer raises go to the shell's router. An app that draws no chat (News) is talked to in the shell's "Ask " panel, on the same peer | On main ([#106](https://github.com/OctoSense-org/OctoSense/pull/106), consent from [#120](https://github.com/OctoSense-org/OctoSense/pull/120)) | +| Script app | `host.request("octos.session.open" / "octos.session.history" / "octos.turn.start" / "octos.turn.interrupt", …)` to the `octos` host service (`crates/ai-host/src/contained.rs`); gated by the manifest, `Policy::contained_gate` (`ContainedGate::Consent` by default) and first-use consent; tool approvals its peer raises go to the shell's router. An app that draws no chat (News) is talked to in the shell's "Ask " panel, on the same peer | On main ([#106](https://github.com/OctoSense-org/OctoSense/pull/106), consent from [#120](https://github.com/OctoSense-org/OctoSense/pull/120)) | | Native app in its own process | the **peer link**: its own channel on the app's hub connection (`PeerRequest`, `PeerReply`, `PeerToolCall` with the identity and caller stamped by the shell), never registered with the AI bus; client API in Makepad's `makepad-ai-services` | Shell side on main ([#130](https://github.com/OctoSense-org/OctoSense/pull/130), `crates/shell/src/peer_link/`, frames routed from the hub connection in `lib.rs`); no process app is granted an agent yet | ### Makepad's AI services bus vs OctoSense's app agents @@ -445,7 +445,7 @@ Found while writing this page (2026-09-28) and rechecked against `main` on 2026- 2. **Restart of a dead process app.** Fixed ([#130](https://github.com/OctoSense-org/OctoSense/pull/130)): an unexpected death keeps the tile, closed with a Restart (`ClientSlot::stops_in_place`; test `an_unexpected_death_keeps_the_tile_closed_with_restart`). 3. **Agent workspace = account folder.** Partly fixed: a peer created since the octos 665209e5 pin gets its account folder as the `peer/prepare` `cwd`; a peer created before keeps the kernel-provisioned workspace, because octos resumes a peer only under the workspace it was made with (moving it needs a migration octos does not offer). The account folder name (`account_hash`, SHA-256) and the memory namespace tag (FNV-1a in `broker.rs`) are still different hashes of the account; changing the tag would re-key every app's memory ([#139](https://github.com/OctoSense-org/OctoSense/issues/139)). 4. **ADR 0003 "What the profile runs"** says OctoSense configures neither the tool set nor the sandbox. Since [#117](https://github.com/OctoSense-org/OctoSense/pull/117) the shell writes a `tool_policy` denying `group:runtime` into the `_main` profile before every start, so the host's own turns have no octos shell either. Fixed in the text: ADR 0003 carries a dated amendment (2026-09-29), as do ADR 0002 §12 and its amendment. (Fixed, G13: when `enforce` refuses a foreign policy or the person's own octos home, or the policy does not read back, the kernel does not start and every consumer is told why; and each app peer keeps exactly its granted `generic_tools`, never the shell.) -5. **Stale context lines.** Fixed: ADR 0004's context table and the README layout tables no longer list the native News, Maps and Photos modules ADR 0004 step 1 deleted (#113), and [ai-services.md](ai-services.md) now describes `main` on 2026-09-28 (the Card runner's `octos` service from #106, consent from #120; the `Policy::contained_apps` switch is still off by default). +5. **Stale context lines.** Fixed: ADR 0004's context table and the README layout tables no longer list the native News, Maps and Photos modules ADR 0004 step 1 deleted (#113), and [ai-services.md](ai-services.md) now describes `main` on 2026-09-28 (the Card runner's `octos` service from #106, consent from #120; the current `Policy::contained_gate` defaults to `ContainedGate::Consent`, not globally off). 6. **Command execution "turned on in Settings".** Fixed: Setup › Assistant › Command execution sets it (#132), and the system chat registers `terminal.run` on the system session while it is on. 7. **`host::processes_available()`'s test** checks only `wasm32` while the function also excludes native mobile. 8. **Approvals, ADR 0004 §8.** Every app tool call reaches the shell through `peer/tool/call` and every gated one the router (above). No app registers its own `confirm: app` sheet yet (Rinx needs to hand its send sheet over through `OctosAppService::set_confirm_sheet`), so such a call would wait and be refused. The audit keeps a digest of the arguments, not the arguments. The send queue and undo window are not built. @@ -453,7 +453,8 @@ Found while writing this page (2026-09-28) and rechecked against `main` on 2026- 10. **Developer mode, ADR 0004 §13.** Fixed: `dev.run` is registered on covered apps' peers and run by the shell. Fixed: Settings chooses the apps it covers (the desktop's Setup › Developer options, a phone's About phone › Developer options), and a phone reveals Developer options with seven taps on Build number, then turns it on there with a confirmation. Open: in-process modules still show their own confirmation sheets. 11. **Questions, ADR 0004 §6 (decided 2026-09-29).** Agents ask with octos's `ask_user_question` and the shell routes each question to the app's conversation or the system chat; `host.ask` is dropped. Fixed: the broker forwards an app peer's `user_question/requested` to the shell's request model (`crates/shell/src/questions/`), which routes it by the turn's origin to the app's conversation or the system chat; only the person answers, on a shell surface (cards never answer). An agent asks only when its `generic_tools` list `ask_user_question`. 12. **Process sandboxes, ADR 0004 §3.** Only the macOS sandbox is built and tested; Linux is built but unvalidated (#138) and Windows is not built (#137). -13. **App agents, from the 2026-09-29 code review** (octos acffad3b, `main` ecb3583; listed in ADR 0004's follow-ups): kernel-tool approvals on a `peer/input` turn are dropped by the broker's event filter for the peer session (`broker.rs`), so nobody can answer them; contained script apps' cards get no streaming, have every approval declined, share one context per app and use the fixed account `device` (`crates/ai-host/src/contained.rs`); a failed host `turn/start` for a `peer/input` is only logged; the `peer/input` route belongs to whichever connection registered the peer's tools last (untested with several instances). +13. **App-agent follow-ups from the 2026-09-29 review, rechecked 2026-10-01.** The old blanket claims that approvals are dropped, every app uses `device`, and failed input starts are only logged no longer describe the implementation. `broker.rs::on_user_question`/approval routing hand prompts to the host; `contained.rs::account_of` consults the host account source; input-start failures use `peer/input/reject`; `driver_of`/`take_over` coordinate multiple brokers for one peer. The `broker` tests exercise these paths. The contained `host.request` adapter still returns a collected turn reply rather than a script-visible streaming subscription; native contexts and the shell's chat surfaces have event subscriptions. `implemented_by: "app"` script tool dispatch, bundle `AGENT.md` prompt loading and automatic skills/triggers remain unimplemented. Read the [walkthrough](architecture-walkthrough.md) for the exact current boundaries. + ## Source map diff --git a/docs/architecture.zh-CN.md b/docs/architecture.zh-CN.md index a542af3d..9906980d 100644 --- a/docs/architecture.zh-CN.md +++ b/docs/architecture.zh-CN.md @@ -2,7 +2,7 @@ [English](architecture.md) | 简体中文 -OctoSense 的各部分如何组合在一起:每个平台上运行哪些进程、Agent 在哪里、各部分如何通信、工具如何授权和审批、数据与机密存放在哪里,以及信任边界在哪里。本文描述 2026-09-28 的 `main`(OctoSense `ff40e9c`,它锁定 octos `5e7577f0`),内容均在代码中读过。 +OctoSense 的各部分如何组合在一起:每个平台上运行哪些进程、Agent 在哪里、各部分如何通信、工具如何授权和审批、数据与机密存放在哪里,以及信任边界在哪里。最新[初学者代码导读](architecture-walkthrough.zh-CN.md)于 2026-10-01 核对 OctoSense `c19da8d` 及其 octos `ae230ce0` 锁定版本。本文保留标注日期的设计/审查历史;下列修订反映该源码快照。 每条陈述都标明状态: @@ -178,7 +178,7 @@ flowchart TB 目前谁有 peer(`crates/ai-host/src/lib.rs`,`Policy::shipped()`;`crates/app-peers/src/hosted.rs`,`effective_services` = 声明 ∩ 支持 ∩ 策略): - **Rinx**,唯一获授权使用助手的原生应用(四个 `octos.*` 服务),需首次使用时的同意。 -- **带 Agent 的脚本应用**:清单声明了 `octos.*` 或 `agent` 块,或应用包带有 `tools.json`(如 News)。每个应用一个 peer `card.`,账号为 `device`(`crates/ai-host/src/contained.rs`,[#106](https://github.com/OctoSense-org/OctoSense/pull/106)),在用户首次使用同意后可用(发布策略;`OCTOSENSE_CONTAINED_APPS=1` 不再询问,`0` 关闭)。用户一旦同意(以及启动时对已同意的应用),Shell 就会准备其 peer(`crates/shell/src/agents.rs`),因此即使应用从不调用 `octos`,系统 Agent 的 `peer_list` 也能看到它;对尚未同意或已关闭的应用,Shell 通过系统聊天中的提示以及 `agents.list` / `agents.ask` 宿主工具告知系统 Agent。 +- **带 Agent 的脚本应用**:清单声明了 `octos.*` 或 `agent` 块,或应用包带有 `tools.json`(如 News)。每个应用/账号一个 peer,broker 身份为 `card.`;无账号应用使用 `device`,Mail 等使用宿主报告的已登录账号(`crates/ai-host/src/contained.rs`,[#106](https://github.com/OctoSense-org/OctoSense/pull/106)),在用户首次使用同意后可用(发布策略;`OCTOSENSE_CONTAINED_APPS=1` 不再询问,`0` 关闭)。用户一旦同意(以及启动时对已同意的应用),Shell 就会准备其 peer(`crates/shell/src/agents.rs`),因此即使应用从不调用 `octos`,系统 Agent 的 `peer_list` 也能看到它;对尚未同意或已关闭的应用,Shell 通过系统聊天中的提示以及 `agents.list` / `agents.ask` 宿主工具告知系统 Agent。 - **AppCard**(可选)使用自己的内核连接和会话,而不是 peer。 - 进程应用目前没有 Agent:只有 `ModuleHost::create` 中才会提供服务(peer link 规划中,步骤 8)。 @@ -245,7 +245,7 @@ flowchart LR | --- | --- | --- | | 进程内原生模块,经 peer link | Makepad 的 `OctosPeer::open` 暂存一对通道;模块宿主把它归给打开它的实例,Shell 用进程应用同一套 **peer link** 服务它(`peer_link::module_connected`、`octosense_ai_host::module_peer`),应用无需知道自己如何被承载 | 已在 main([#142](https://github.com/OctoSense-org/OctoSense/issues/142));尚无模块使用 | | 进程内原生模块(Rinx) | **注入的服务**:`create` 之前调用 `ai_host::offer`,在其中调用 `octosense_app_peers::injection::claim`,得到受限的 `OctosAppService`(`Open`、`History`、`Turn`、`Interrupt`、`Approval`);模块永远看不到协议 | 已在 main | -| 脚本应用 | 向 `octos` 宿主服务(`crates/ai-host/src/contained.rs`)调用 `host.request("octos.session.open" / "octos.session.history" / "octos.turn.start" / "octos.turn.interrupt", …)`;受清单、`Policy::contained_apps` 和首次使用同意(`consent_for_contained`)约束;其 peer 发起的工具审批一律被拒绝,并列在 `denied_approvals` 中 | 已在 main([#106](https://github.com/OctoSense-org/OctoSense/pull/106),同意机制来自 [#120](https://github.com/OctoSense-org/OctoSense/pull/120)) | +| 脚本应用 | 向 `octos` 宿主服务(`crates/ai-host/src/contained.rs`)调用 `host.request("octos.session.open" / "octos.session.history" / "octos.turn.start" / "octos.turn.interrupt", …)`;受清单、`Policy::contained_gate`(默认 `ContainedGate::Consent`)和首次使用同意约束;其 peer 的工具审批交给 Shell 审批路由,只有用户通过宿主界面回答 | 已在 main([#106](https://github.com/OctoSense-org/OctoSense/pull/106),同意机制来自 [#120](https://github.com/OctoSense-org/OctoSense/pull/120)) | | 独立进程的原生应用 | **peer link**:应用 hub 连接上的独立通道(`PeerRequest`、`PeerReply`,以及由 Shell 盖上身份和调用方的 `PeerToolCall`),从不注册到 AI 总线;客户端 API 在 Makepad 的 `makepad-ai-services` 中 | 规划中(ADR 0004 §5,步骤 8);`hub.rs` 中尚无代码 | ### Makepad 的 AI 服务总线与 OctoSense 的应用 Agent @@ -438,19 +438,20 @@ sequenceDiagram ## 代码与 ADR 不一致之处 -撰写本文时(2026-09-28)发现;本次改动只涉及文档,这里都没有修复。 +下列记录始于 2026-09-28;已修复项随后由代码或 ADR 变更解决。应用 Agent 的关键路径于 2026-10-01 重新核对,见最后一项。 1. **Terminal 之外的进程应用。** 已修复:可选的 Sheets 和 Reference 在所有目标上都是 `module`,生成器拒绝 Linux 上的普通 `process`(ADR 0004 §2)。 2. **崩溃进程应用的重启。** ADR 0004 §2 说它的磁贴会显示已关闭并提供重启。Shell 实际上移除客户端并发出 “App stopped” 通知;Restart 界面只用于进程内模块(`module_view.rs`)。 3. **Agent 工作区 = 账号目录。** 部分修复:自锁定 octos 665209e5 起新建的 peer 以账号目录作为 `peer/prepare` 的 `cwd`;之前创建的 peer 保留内核分配的工作区,因为 octos 只允许在创建时的工作区下恢复 peer(迁移需要 octos 尚未提供的支持)。账号目录名(`account_hash`,SHA-256)和记忆命名空间标签(`broker.rs` 中的 FNV-1a)仍是对账号的两种不同 hash;改动标签会让每个应用的记忆重新计算键。 4. **ADR 0003 的 “What the profile runs”** 说 OctoSense 既不配置工具集也不配置沙箱。自 [#117](https://github.com/OctoSense-org/OctoSense/pull/117) 起,Shell 每次启动前都向 `_main` profile 写入拒绝 `group:runtime` 的 `tool_policy`,因此宿主自己的回合也没有 octos shell。 -5. **过时的背景描述。** 已修复:ADR 0004 的背景表格和各 README 的目录结构表不再列出 ADR 0004 步骤 1 删除的原生 News、Maps 和 Photos 模块(#113)。[ai-services.zh-CN.md](ai-services.zh-CN.md) 现已描述 2026-09-28 的 `main`(#106 的 Card runner `octos` 服务、#120 的同意机制;`Policy::contained_apps` 开关默认仍关闭)。 +5. **过时的背景描述。** 已修复:ADR 0004 的背景表格和各 README 的目录结构表不再列出 ADR 0004 步骤 1 删除的原生 News、Maps 和 Photos 模块(#113)。[ai-services.zh-CN.md](ai-services.zh-CN.md) 现已描述 2026-09-28 的 `main`(#106 的 Card runner `octos` 服务、#120 的同意机制;当前 `Policy::contained_gate` 默认是 `ContainedGate::Consent`,不是全局关闭)。 6. **“在 Settings 中开启”命令执行。** 已修复:Setup › Assistant › Command execution 设置它(#132),开启期间系统对话把 `terminal.run` 注册到系统会话。 7. **`host::processes_available()` 的测试**只检查 `wasm32`,而函数本身还排除了原生移动平台。 8. **审批,ADR 0004 §8。** 每次应用工具调用都通过 `peer/tool/call` 到达 Shell,每个有门控的调用都到达路由(见上文)。还没有应用注册自己的 `confirm: app` 面板(Rinx 需要通过 `OctosAppService::set_confirm_sheet` 交出它的发送面板),因此这类调用会等待后被拒绝。审计记录的是参数摘要而不是参数。发送队列和撤销窗口尚未实现。 9. **存储,ADR 0004 §11。** 机密只在 macOS 和 iOS 上使用系统钥匙串(其他平台为 0600 明文文件)。启动检查拒绝通过链接或包含关系通向机密的工作区,而不是查找 `secrets/` 路径,并且不会中止启动。(已修复:app storage 和同意面板中 `storage.accounts` 都默认为 `false`,同意面板现在读取 `StorageSpec`。) 10. **开发者模式,ADR 0004 §13。** 已修复:`dev.run` 已注册在被覆盖应用的 peer 上,由 shell 执行。已修复:Settings 可以选择覆盖哪些应用(桌面端在 Setup › Developer options,手机上在 About phone › Developer options),手机上连续点按 Build number 七次显示 Developer options,再在那里确认开启。未完成:进程内模块仍会显示自己的确认面板。 -11. **应用 Agent,来自 2026-09-29 的代码审查**(octos acffad3b、`main` ecb3583;列在 ADR 0004 的后续事项中):`peer/input` 回合上内核工具的审批被 broker 对 peer 会话的事件过滤丢弃(`broker.rs`),无人能回答;受限脚本应用的卡片没有流式输出、所有审批都被拒绝、每个应用共用一个上下文并使用固定账号 `device`(`crates/ai-host/src/contained.rs`);卡片从不回答 `user_question/requested`:问题由 Shell 的请求模型按回合发起者路由,只由用户在 Shell 界面上回答(已修复);`peer/input` 的宿主 `turn/start` 失败只记日志;`peer/input` 路由归最后注册该 peer 工具的连接所有(多实例未测试)。 +11. **2026-09-29 应用 Agent 审查的后续,2026-10-01 复核。** “所有审批被丢弃”“全部固定为 `device`”“输入启动失败只记日志”等旧描述已不符合当前实现。broker 将问题/审批交给宿主;`contained.rs::account_of` 获取宿主账号;失败的系统输入使用 `peer/input/reject`;`driver_of`/`take_over` 协调同一 peer 的多个 broker,相关路径有 broker 测试。受限 `host.request` 适配器仍返回汇总回合回复,没有脚本可订阅的流式接口;原生 context 和 Shell 聊天则有事件订阅。`implemented_by: "app"` 的脚本工具执行、`AGENT.md` 提示词加载和自动技能/触发器仍未实现。确切边界见[代码导读](architecture-walkthrough.zh-CN.md)。 + ## 源码位置 diff --git a/phone/AGENTS.md b/phone/AGENTS.md new file mode 100644 index 00000000..d6bd684b --- /dev/null +++ b/phone/AGENTS.md @@ -0,0 +1,24 @@ +# Working on Home + +Follow the [repository rules](../AGENTS.md) and the +[product source walkthrough](../desktop/docs/code-walkthrough.md). + +- Run Home Cargo commands from `phone/`: `.cargo/config.toml` selects its + system bundles. `mobile-only` chooses phone presentation on desktop; + `mobile-apps` links extra native modules. They are not synonyms. +- Keep shared shell changes in `../crates/shell/`. Home's `App` wraps the + shared `App` and adds Settings; preserve the before/after event ordering in + `src/main.rs` when changing platform integration. +- Settings is privileged through its compiled trusted module identity, not a + script-provided name. Preserve request attribution, freshness, correlation + and observed-state checks at Rust/Java boundaries. +- The octos system agent, System Bridge and ROM `AgentPlatformService` are + distinct components. Binder permissions are not LLM tool grants. Standalone + Home does not gain the ROM's platform signature or permissions. +- APK building, installation and ROM flashing are separate operations. Follow + `../rom/docs/home-build.md` for the supported Home/Bridge build. Use only an + assigned device and a separate test package; no device result may be inferred + from desktop preview or compilation. +- Apply the root's phone checks to code changes. For doc-only changes, check + paths, features and links, keep README languages paired, and label unrun + build/device instructions unverified. diff --git a/phone/README.md b/phone/README.md index 52dfa3bb..091e5ac8 100644 --- a/phone/README.md +++ b/phone/README.md @@ -2,7 +2,9 @@ English | [简体中文](README.zh-CN.md) -> **Where this fits.** On a phone every app runs in the Home process (there are no process apps); the octos kernel is the APK's `liboctos.so` as a child process on Android, an in-process task on OpenHarmony, and absent on iOS. Apps still reach their agents only through the shell. Diagrams of the processes, an app agent's two lanes and a tool call with its approval: [How it fits together](../README.md#how-it-fits-together); the details: [docs/architecture.md](../docs/architecture.md) and [ADR 0004](../docs/adr/0004-native-apps-hosting-and-peers.md). +**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, real app data and Android platform boundaries; it marks unrun recipes explicitly. + +> **Where this fits.** On a phone, OctoSense-hosted native modules and script apps run in the Home process (no desktop-style hosted process apps); ordinary Android apps still run in their own Android processes. The octos kernel is the APK's `liboctos.so` as a child process on Android, an in-process task on OpenHarmony, and absent on iOS. Apps still reach their agents only through the shell. Diagrams of the processes, an app agent's two lanes and a tool call with its approval: [How it fits together](../README.md#how-it-fits-together); the details: [docs/architecture.md](../docs/architecture.md) and [ADR 0004](../docs/adr/0004-native-apps-hosting-and-peers.md). The OctoSense phone shell: a Makepad app that is the device's Home screen. Home pages with live tiles and app pairs, a gesture layer, the shade diff --git a/phone/README.zh-CN.md b/phone/README.zh-CN.md index 693987a2..3a70f3c5 100644 --- a/phone/README.zh-CN.md +++ b/phone/README.zh-CN.md @@ -2,7 +2,9 @@ [English](README.md) | 简体中文 -> **在整个系统中的位置。**在手机上所有应用都在 Home 进程内运行(没有进程应用);octos 内核在 Android 上是 APK 中作为子进程运行的 `liboctos.so`,在 OpenHarmony 上是进程内的任务,在 iOS 上没有。应用仍然只能通过 Shell 使用自己的 Agent。进程、应用 Agent 的两条通道以及一次带审批的工具调用的图示:[整体如何运作](../README.zh-CN.md#整体如何运作);详细说明:[docs/architecture.zh-CN.md](../docs/architecture.zh-CN.md) 和 [ADR 0004(英文)](../docs/adr/0004-native-apps-hosting-and-peers.md)。 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、真实数据和 Android 平台边界,并明确标注未运行的配方。 + +> **在整个系统中的位置。**在手机上,OctoSense 托管的原生模块和脚本应用在 Home 进程内运行(不使用桌面式进程托管);普通 Android 应用仍在各自的 Android 进程中运行。octos 内核在 Android 上是 APK 中作为子进程运行的 `liboctos.so`,在 OpenHarmony 上是进程内的任务,在 iOS 上没有。应用仍然只能通过 Shell 使用自己的 Agent。进程、应用 Agent 的两条通道以及一次带审批的工具调用的图示:[整体如何运作](../README.zh-CN.md#整体如何运作);详细说明:[docs/architecture.zh-CN.md](../docs/architecture.zh-CN.md) 和 [ADR 0004(英文)](../docs/adr/0004-native-apps-hosting-and-peers.md)。 OctoSense 手机 Shell:一个 Makepad 应用,也就是设备的桌面。它包括带实时磁贴和应用组合的桌面页面、手势层、通知面板(左侧通知,右侧控制)、最近任务、用于展示进行中活动的实时岛,以及在进程内绘制于磁贴中的托管应用:App Hub 及其运行的应用、系统应用、Reference 和 Sheets,另外还有作为服务的 octos Agent 内核。(AppCard 目前不随产品发布,只有使用 `--features app-appcard` 时才会链接。) diff --git a/phone/android/README.md b/phone/android/README.md index 4764192a..026b6819 100644 --- a/phone/android/README.md +++ b/phone/android/README.md @@ -55,17 +55,20 @@ Outputs: - `quickstep/build/outputs/apk/prototype/quickstep-prototype.apk`. Build the Makepad packager in the pinned checkout `.sources/makepad` (prepared -by `python3 scripts/setup-home.py`) after its source changes, then invoke its -standalone binary from `home/`. This builds without installing: +by `python3 tools/setup.py` from the repository root) after its source changes, then invoke its +standalone binary from `phone/`. This builds without installing. +**Unverified in this documentation review**; this low-level command is not the +Home/Bridge pair build or kernel receipt pipeline. Use +[the supported build](../README.md#build-and-run) for those artifacts: ```sh # From .sources/makepad: cargo build --locked --offline --release -p cargo-makepad -# From home/, with an existing Makepad SDK selected: -../.sources/makepad/target/release/cargo-makepad android \ +# From phone/, with an existing Makepad SDK selected: +../.sources/makepad/target/release/cargo-makepad makepad android \ --sdk-path="$OCTOSENSE_MAKEPAD_SDK" --abi=aarch64 \ - build --release --locked --offline --no-default-features -p octosense + build --release --locked --offline -p octosense-home ``` The packager compiles `resources/android/java/` and includes JARs from @@ -83,7 +86,7 @@ and preserves their data. Retain a checksum-verified rollback APK and record device settings before testing a user-owned phone. Build the bridge runner with `:system-bridge:assembleValidation` and -`:system-bridge:lintValidation`. From `home/`, build the Home runner: +`:system-bridge:lintValidation`. From `phone/`, build the Home runner: ```sh python3 android/scripts/build-home-validation.py \ diff --git a/phone/android/README.zh-CN.md b/phone/android/README.zh-CN.md index 0cdf1e13..1de90539 100644 --- a/phone/android/README.zh-CN.md +++ b/phone/android/README.zh-CN.md @@ -31,16 +31,16 @@ export GRADLE_USER_HOME="$OCTOSENSE_TOOLS/gradle-cache" - `system-bridge/build/reports/lint-results-prototype.html`。 - `quickstep/build/outputs/apk/prototype/quickstep-prototype.apk`。 -Makepad 打包器的源码变更后,在固定版本的检出目录 `.sources/makepad`(由 `python3 scripts/setup-home.py` 准备)中构建它,然后在 `home/` 下调用其独立二进制文件。以下命令只构建、不安装: +Makepad 打包器的源码变更后,在固定版本的检出目录 `.sources/makepad`(在仓库根目录运行 `python3 tools/setup.py` 准备)中构建它,然后在 `phone/` 下调用其独立二进制文件。以下命令只构建、不安装,**本次文档审查未验证**。这是底层打包命令,不是 Home/Bridge 配对构建与内核回执流水线;完整产物请使用 [Home README 的构建流程](../README.zh-CN.md): ```sh # From .sources/makepad: cargo build --locked --offline --release -p cargo-makepad -# From home/, with an existing Makepad SDK selected: -../.sources/makepad/target/release/cargo-makepad android \ +# From phone/, with an existing Makepad SDK selected: +../.sources/makepad/target/release/cargo-makepad makepad android \ --sdk-path="$OCTOSENSE_MAKEPAD_SDK" --abi=aarch64 \ - build --release --locked --offline --no-default-features -p octosense + build --release --locked --offline -p octosense-home ``` 打包器会编译 `resources/android/java/`,并将 `resources/android/libs/` 中的 JAR 同时加入 javac 和 D8 的输入。构建 Home 之前请先导出契约。框架现有的 SDK 目录结构与这里的 Gradle SDK 相互独立;单纯的跨目标 `cargo check` 同样需要已安装的 NDK 编译器环境,这通常由打包器提供。 @@ -49,7 +49,7 @@ cargo build --locked --offline --release -p cargo-makepad 常规 Home、bridge `prototype` 和 bridge `release` 的清单均不包含 instrumentation 注册。验证 APK 使用相同的应用身份和签名关系;安装后会替换这些应用并保留其数据。在用户自有手机上测试前,请保留一份经过校验和验证的回滚 APK,并记录设备设置。 -使用 `:system-bridge:assembleValidation` 和 `:system-bridge:lintValidation` 构建 bridge 测试运行器。在 `home/` 下构建 Home 测试运行器: +使用 `:system-bridge:assembleValidation` 和 `:system-bridge:lintValidation` 构建 bridge 测试运行器。在 `phone/` 下构建 Home 测试运行器: ```sh python3 android/scripts/build-home-validation.py \ diff --git a/rom/AGENTS.md b/rom/AGENTS.md new file mode 100644 index 00000000..1f88ec99 --- /dev/null +++ b/rom/AGENTS.md @@ -0,0 +1,19 @@ +# Working on the ROM + +The [repository rules](../AGENTS.md) apply. Read the +[product source walkthrough](../desktop/docs/code-walkthrough.md) and +[Home build contract](docs/home-build.md) before changing packaging docs. + +- `vendor/octosense/` is the Android product/platform layer. Home and the + System Bridge are built from `../phone/`; do not revive a `home/` source copy. +- The Java/Binder privileged agent is not the octos LLM system agent. Document + package/signature gates separately from assistant consent/tool policy. +- Keep build, artifact receipt verification, staging, signing, installation, + flashing and release steps explicit. A successful build is not evidence that + the image boots or that platform functions work. +- Do not install, flash or publish as part of a documentation review. Device + work requires the user's assigned device and authorized scope. Keep signing + material and machine paths outside this repository. +- Run the applicable Python/script checks from the root instructions for code + changes. For docs, check relative links and source-backed command arguments, + pair README languages and mark unexecuted commands/device work unverified. diff --git a/rom/README.md b/rom/README.md index 01b964f8..722b1ddf 100644 --- a/rom/README.md +++ b/rom/README.md @@ -2,6 +2,8 @@ English | [简体中文](README.zh-CN.md) +**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, real app data and Android platform boundaries; it marks unrun recipes explicitly. + The OctoSense ROM is LineageOS 22.2 (Android 15) for the OnePlus 6 (`enchilada`) with the OctoSense Home app preinstalled beside a privileged agent, Quickstep and SystemUI, so the agent reaches the system layer. This diff --git a/rom/README.zh-CN.md b/rom/README.zh-CN.md index ef6f67eb..6092b41c 100644 --- a/rom/README.zh-CN.md +++ b/rom/README.zh-CN.md @@ -2,6 +2,8 @@ [English](README.md) | 简体中文 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、真实数据和 Android 平台边界,并明确标注未运行的配方。 + OctoSense ROM 是面向 OnePlus 6(一加 6,`enchilada`)的 LineageOS 22.2(Android 15),预装 OctoSense Home 应用以及具有系统权限的 agent、Quickstep 和 SystemUI,让 Agent 进入系统层。本目录只包含镜像本身:产品层、补丁、构建/签名/刷写/更新镜像的脚本,以及网页安装器。它原是 OctoSense-ROM 仓库(已停用,并入本仓库;其中的 `home/` 现为 [`../phone/`](../phone/README.zh-CN.md));见 [ADR 0001(英文)](../docs/adr/0001-one-octosense-repository.md)。 Home 应用本身(也可作为普通 Home 应用安装在任意 Android 手机上)从 [`../phone/`](../phone/README.zh-CN.md) 构建。镜像使用这个以平台密钥签名的 APK,并加上具有系统权限的系统侧组件。 From c3011a2057ec59738b79466f48ff2ad8d0e60130 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:57:55 -0700 Subject: [PATCH 2/6] docs: resolve architecture review and correct unsupported tool guidance --- AGENTS.md | 16 +- README.md | 20 +- README.zh-CN.md | 19 +- apps/AGENTS.md | 55 +-- apps/README.md | 55 +-- apps/README.zh-CN.md | 47 +-- apps/appcard/AGENTS.md | 14 +- apps/appcard/README.md | 4 +- apps/appcard/README.zh-CN.md | 5 +- crates/kernel/README.zh-CN.md | 2 +- crates/shell/src/host_tools/script_apps.rs | 2 +- desktop/AGENTS.md | 35 +- desktop/README.md | 2 +- desktop/README.zh-CN.md | 2 +- desktop/docs/code-walkthrough.md | 434 +++++++++++---------- desktop/docs/code-walkthrough.zh-CN.md | 266 +++++++++---- docs/ai-services.md | 20 +- docs/ai-services.zh-CN.md | 22 +- docs/architecture-walkthrough.md | 79 ++-- docs/architecture-walkthrough.zh-CN.md | 271 ++++++++----- docs/architecture.md | 24 +- docs/architecture.zh-CN.md | 20 +- phone/AGENTS.md | 41 +- phone/README.md | 6 +- phone/README.zh-CN.md | 4 +- phone/android/README.md | 3 +- phone/android/README.zh-CN.md | 2 +- rom/AGENTS.md | 36 +- rom/README.md | 2 +- rom/README.zh-CN.md | 2 +- 30 files changed, 884 insertions(+), 626 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 5b92a9cb..cda29a70 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -52,12 +52,10 @@ On a machine that already has clones of Makepad, OctoScript or Octoscript-Makepa ## Architecture documentation and code walkthroughs -For an unfamiliar subsystem, start with [the junior-Rust walkthrough](docs/architecture-walkthrough.md) and [the product walkthrough](desktop/docs/code-walkthrough.md), then follow their source symbols. Keep the English/Chinese guides and README entry points aligned when a boundary changes. - -- Trace the checked-out implementation and the root Cargo/runtime pins. Do not mix old `home/` worktrees or archived System-Apps/AppCard repositories into current product instructions. -- Separate application hosting (Rust module/process, contained Splash app, L0 card) from agent identity (peer/session/context) and execution (UI thread, worker thread, Tokio task/runtime). -- When documenting an app operation, verify its manifest, admitted `tools.json`, grant and executable handler. A UI host-service API, `shareable` flag or accepted `AGENT.md`/trigger file does not prove an agent can execute it. -- Distinguish an app account workspace, host-service database, kernel memory and host secrets. Check accountless `device` and signed-in account paths separately. -- Keep human conversation contexts distinct from the system-lane peer session; never describe all app instances as independent peers or all peers as one task each. -- Check cross-app claims at both App Hub admission (`HostLimits.offered_tools`) and the shell relay. A route supported by the relay can still be rejected at admission. -- Report unit/scripted-connector tests separately from optional real-kernel suites that early-return without binary environment variables. Mark unrun UI, provider, mobile and ROM commands unverified. +Start with the [architecture walkthrough](docs/architecture-walkthrough.md) and [product walkthrough](desktop/docs/code-walkthrough.md), then follow the source symbols. Update English/Chinese guides and README entry points together when changing a boundary. + +- For hosting changes, document the module/process/Splash/card loader and its identity source in `module_host`, `peer_link`, or App Hub's runner. +- For agent changes, trace `contract.rs` → `broker.rs` → the owning executor. Describe the peer/account identity, system session and human context separately from their runtime tasks. +- For a new tool, update its manifest, `tools.json`, admission offer, caller grant and executable handler. Show which host service or workspace owns its data and how approval reaches the router. +- Read external code at the Cargo/runtime pins. Use current `desktop/`, `phone/`, `rom/` and `apps/` paths when writing product instructions. +- Record test execution in the PR: distinguish unit/scripted connectors from optional real-kernel tests that return early without a binary. Mark unrun launch/device recipes unverified. diff --git a/README.md b/README.md index 8d00b37b..e2767520 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,11 @@ It was OctoSense-Desktop; OctoSense-ROM (retired; merged into this repository) a ## Start with the code walkthrough -For junior Rust developers, [From an app window to an agent turn](docs/architecture-walkthrough.md) follows executable entry points, native and script hosting, app data access, human/system conversations, tool routing and the actual Tokio tasks. The [product walkthrough](desktop/docs/code-walkthrough.md) adds desktop, Home, ROM and system-app run recipes. These guides distinguish source inspection, executed checks and unverified device/model runs. +New to the codebase? Start with [From an app window to an agent turn](docs/architecture-walkthrough.md). It follows executable entry points, native and script hosting, app data access, human/system conversations, tool routing and the actual Tokio tasks. The [product walkthrough](desktop/docs/code-walkthrough.md) adds desktop, Home, ROM and system-app run recipes. ## How it fits together -One shell process per device, one octos kernel per shell, and every agent is a session in that kernel. Apps never talk to the kernel: every path into octos goes through the shell, which holds the host connection and the host token, relays every agent tool call to the app that owns the tool, and puts every approval in front of the person. The full picture, with the code paths and what is on `main` versus planned: [docs/architecture.md](docs/architecture.md); the decisions: [ADR 0004](docs/adr/0004-native-apps-hosting-and-peers.md). +One shell process per device, one octos kernel per shell, and every agent is a session in that kernel. App-agent access goes through the shell broker. The shell holds the host connection and the host token, relays every agent tool call to the app that owns the tool, and routes approvals through developer mode, the person's standing rules or confirmation sheets. The opt-in AppCard prototype accesses the shared kernel service directly, bypassing the app-peer broker, as described below. The full picture, with the code paths and what is on `main` versus planned: [docs/architecture.md](docs/architecture.md); the decisions: [ADR 0004](docs/adr/0004-native-apps-hosting-and-peers.md). ### Processes and connections @@ -83,16 +83,20 @@ flowchart LR ### The system agent and the app agents -**The system agent** is the kernel session `_main:api:octosense#system` on the `_main` profile (`crates/kernel/src/network.rs`). It owns every app agent and supervises them. The person talks to it in the shell's **assistant pane**, the system chat (`crates/shell/src/system_chat/`: the dock's Assistant icon, the phone home's Assistant tile or F8; a medium pane at the left on a desktop that moves and resizes and renders Markdown, full screen on a phone), or from a paired Talk to Octos client. Its kernel tools are exactly `SYSTEM_AGENT_TOOLS` (`crates/kernel/src/system_tools.rs`): `peer_send_input`, `peer_gather`, `peer_list` and `peer_respond` to supervise app agents, its workspace's file tools, memory, `ask_user_question`, media viewing, `web_search`, `web_fetch` and `tool_search`. Every kernel start sets that list with octos's `session/tool_list/set`, so octos's own shell, the spawn family and `peer_close` are never offered. The system chat also registers host tools on the session: `agents.list` and `agents.ask` (`crates/shell/src/agents.rs`: which apps have an agent, and the first-use sheet for one), and `terminal.run` while Setup › Assistant › Command execution is on. +**The system agent** is the kernel session `_main:api:octosense#system` on the `_main` profile (`crates/kernel/src/network.rs`). It owns every app agent and supervises them. The person talks to it in the shell's **assistant pane**, the system chat (`crates/shell/src/system_chat/`: the dock's Assistant icon, the phone home's Assistant tile or F8; a medium pane at the left on a desktop that moves and resizes and renders Markdown, full screen on a phone), or from a paired Talk to Octos client. Its kernel tools are exactly `SYSTEM_AGENT_TOOLS` (`crates/kernel/src/system_tools.rs`): `peer_send_input`, `peer_gather`, `peer_list` and `peer_respond` to supervise app agents, its workspace's file tools, memory, `ask_user_question`, media viewing, `web_search`, `web_fetch` and `tool_search`. Every kernel start sets that list with octos's `session/tool_list/set`, so octos's own shell, the spawn family and `peer_close` are never offered. The system chat also registers host tools on the session: `agents.list` and `agents.ask` (`crates/shell/src/agents.rs`: which apps have an agent, and the first-use sheet and ready-peer wait for one), and `terminal.run` while Setup › Assistant › Command execution is on. **An app agent** is one host-owned octos peer per (app, account) ([`crates/app-peers`](crates/app-peers/README.md)). These apps have one on `main` (`crates/shell/src/apps.rs`, `agent_apps`): | App | Declared by | Its tools (run by) | What it puts on the glance screen | | --- | --- | --- | --- | | Rinx (native) | `native-apps.json` `agent.octos` (the four `octos.*` services) and `agent.generic_tools` | octos's generic tools in its list; its own assistant UI | – | -| News (`os.news`) | `apps/news/bundle/tools.json`, the manifest's `agent` block | `news.list`, `news.read` (the `news` host service) | – | +| News (`os.news`) | `apps/news/bundle/tools.json`, the manifest's `agent` block | `news.list`, `news.read`, `news.notify` (the `news` host service and shell notice callback) | a notice card with a notification | | Mail (`os.mail`) | `apps/mail/bundle/tools.json`, the manifest's `agent` block and `glance` | `mail.notify` (the `mail` host service) | a notice card with a notification | -| Calendar (`os.calendar`, desktop only) | `apps/calendar/bundle/tools.json`, the manifest's `agent` block and `glance` | `calendar.events`, `calendar.add_event`, `calendar.remove_event` (destructive: the person approves it), `calendar.notify`, `calendar.agenda` (the `calendar` host service) | an event card or an agenda card, with a notification | +| Calendar (`os.calendar`, desktop only) | `apps/calendar/bundle/tools.json`, the manifest's `agent` block and `glance` | `calendar.events`, `calendar.add_event`, `calendar.remove_event` (destructive: enters the approval router), `calendar.notify`, `calendar.agenda` (the `calendar` host service) | an event card or an agenda card, with a notification | + +| Photos, Maps, YouTube; Camera on phone | Their bundle `tools.json`, `agent` block and `glance` | Each app's `.notify` (shell `NoticeService`) | a notice card with a notification | + +AI providers has no app agent. A script app has an agent when its manifest declares `octos.*` names or an `agent` block (`"tools": ["ask_user_question"]` names the kernel tools it may use), or its bundle ships `tools.json` (each tool `.` with its schemas, `risk`, `confirm` and `shareable`). Its peer is `card.`. The person allows the agent once, on the first-use sheet (from the shell's "Ask " panel, the app's own `octos` call or the system agent's `agents.ask`). From then on the shell prepares the peer at startup, with the app's tools registered, so the system agent's `peer_list` shows it. On Unix, a consented app agent with an available workspace also gets the host read tools `files.list`, `files.read` and `files.search` over its account folder; these do not expose every host-service database. On the phone, which builds `toolbox-peers` by default, it also gets the system toolbox's tools when its manifest asks for `research` or `crawl`, which no app does yet. `AGENT.md`, skills and triggers ([ADR 0002](docs/adr/0002-event-driven-app-agents.md)) are not built: an app agent runs only when the system agent, the person or a card asks it. @@ -130,7 +134,7 @@ sequenceDiagram -- The model never writes card code: `mail.notify`, `calendar.notify` and `calendar.agenda` fill a fixed L0 card the app's host service ships (`apps/mail/host-service/resources/notice.card`, `apps/calendar/host-service/resources/*.card`) and publish it as the app. +- The notice tools fill `crates/shell/resources/glance/notice.card` through `glance_notice.rs`; Mail and News delegate to it from their host-service callbacks. Calendar ships its own event and agenda templates in `apps/calendar/host-service/resources/`. These tools accept content and publish a fixed L0 template as the app. - `mail.notify` and `calendar.add_event` are `act` tools and run without a sheet; octos asks for approval only for destructive and outward tools, which go to the shell's approval router ([below](#a-tool-call-with-an-approval)). ### One app agent, two lanes @@ -229,7 +233,7 @@ sequenceDiagram - **Tool calls**: octos sends `peer/tool/call` to the shell's relay (`crates/shell/src/host_tools/`), which checks the grant by (owning app, tool) and caller, the arguments against the tool's schema and the caller's budget, and routes the call to the owning app's executor: an in-process module's, a script app's host service, a process app's peer link, or the Terminal's `run` on the AI bus. -- **Approvals** go to the approval router (`crates/shell/src/approvals/`): developer mode, then standing rules on (owning app, tool), then a shell-drawn sheet. A `confirm: app` tool is confirmed on the owning app's own sheet, which shows the caller. Only the person approves; the system agent never does. +- **Approvals** go to `crates/shell/src/approvals/`: external clients retain their prompts; developer mode approves calls for covered apps; `confirm: app` uses the owning app's registered sheet; mandatory live decisions bypass rules; then standing rules may decide, otherwise a shell sheet asks the person. The system agent cannot approve. [The walkthrough](docs/architecture-walkthrough.md#approval-order) gives the complete order, deadlines and audit behavior. - **Deadlines and Stop** ([#167](https://github.com/OctoSense-org/OctoSense/pull/167)): an approval or question the shell holds for an app peer expires after 10 minutes (`OCTOSENSE_PROMPT_DEADLINE_SECS`): the router denies it, a question is declined, both stay visible as "Expired: no answer in 10 min". If the turn is still running 30 s later, the broker interrupts it so the next turn can start. The sheets' "Stop 's agent" ends the running turns of both lanes, the person's and the system agent's; the "Ask " panel's Stop ends only the person's own turn ([above](#talking-to-an-apps-agent-yourself)). - **External clients' prompts** stay with the client: the shell does not answer or expire approvals of a Talk to Octos client's turns (octos#2624). @@ -277,7 +281,7 @@ Related, not build inputs: [OctoScript-App-Design-Flow](https://github.com/OctoS ## AI services (octos) -Each shell runs one [octos](https://github.com/octos-org/octos) agent kernel, started on first use: the APK's `liboctos.so` on Android, in process on OpenHarmony, the binary `OCTOS_APP_CORE_BIN` names on a desktop, none on iOS. The person chooses its models and types keys in the **AI providers** system app, on host sheets; keys stay in the platform's secret store and never reach an app. [`crates/ai-host`](crates/ai-host/README.md) is the shells' one entry point, and [`crates/app-peers`](crates/app-peers/README.md) gives each granted native app its own octos peer (private contexts, workspace and memory `app//acct-`), owned by the shell's system agent. A peer's tool approvals are answered only by the person, in that app; the system agent cannot answer them. +Each shell runs one [octos](https://github.com/octos-org/octos) agent kernel, started on first use: the APK's `liboctos.so` on Android, in process on OpenHarmony, the binary `OCTOS_APP_CORE_BIN` names on a desktop, none on iOS. The person chooses its models and types keys in the **AI providers** system app, on host sheets; keys stay in the platform's secret store and never reach an app. [`crates/ai-host`](crates/ai-host/README.md) is the shells' one entry point, and [`crates/app-peers`](crates/app-peers/README.md) gives each granted native app its own octos peer (private contexts, workspace and memory `app//acct-`), owned by the shell's system agent. Peer tool approvals use the shell router: developer mode, eligible standing rules or a person on the owning app/Shell confirmation sheet. The system agent cannot answer them. What works today: native modules (Rinx) use their peer; AppCard (opt-in) uses the kernel directly. Contained script apps, system or store, reach it through the `octos` host service in a shell that hosts a kernel: each app gets its own host-owned peer (`card.`), and its tool approvals go to the shell's approval sheets like every other app agent's ([#155](https://github.com/OctoSense-org/OctoSense/pull/155)). The `llm` service manages providers for `os.*` apps only. An app's own agent (`tools.json`, `AGENT.md`, skills, triggers, glance cards) is [ADR 0002](docs/adr/0002-event-driven-app-agents.md); host-service-backed `tools.json` tools reach their agents through the shell relay since [#160](https://github.com/OctoSense-org/OctoSense/pull/160). Tools marked `implemented_by: "app"` still lack a Card-runner executor; declaring a tool does not implement it. diff --git a/README.zh-CN.md b/README.zh-CN.md index 82c04b15..453ed650 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -16,11 +16,11 @@ ## 从代码导读开始 -面向 Rust 初学者的[从应用窗口到 Agent 回合](docs/architecture-walkthrough.zh-CN.md),沿着入口、原生/脚本托管、数据访问、人类/系统对话、工具路由以及实际 Tokio 任务阅读源码。[产品导读](desktop/docs/code-walkthrough.zh-CN.md)补充桌面、Home、ROM 和系统应用的运行方式,明确区分源码核对、已执行检查和未验证的设备/模型运行。 +初次阅读源码?从[从应用窗口到 Agent 回合](docs/architecture-walkthrough.zh-CN.md)开始,沿着入口、原生/脚本托管、数据访问、人类/系统对话、工具路由以及实际 Tokio 任务阅读源码。[产品导读](desktop/docs/code-walkthrough.zh-CN.md)补充桌面、Home、ROM 和系统应用的运行方式。 ## 整体如何运作 -每台设备一个 Shell 进程,每个 Shell 一个 octos 内核,每个 Agent 都是这个内核中的一个会话。应用从不直接与内核通信:进入 octos 的每条路径都经过 Shell。Shell 持有宿主连接和宿主 token,把每个 Agent 工具调用转交给拥有该工具的应用,并把每个审批交给用户。完整说明,包括代码路径以及哪些已在 `main` 上、哪些还在规划中:[docs/architecture.zh-CN.md](docs/architecture.zh-CN.md);相关决策:[ADR 0004(英文)](docs/adr/0004-native-apps-hosting-and-peers.md)。 +每台设备一个 Shell 进程,每个 Shell 一个 octos 内核,每个 Agent 都是这个内核中的一个会话。应用 Agent 通过 Shell broker 访问内核。Shell 持有宿主连接和宿主 token,把每个 Agent 工具调用转交给拥有该工具的应用,并通过开发者模式、用户预设的常设规则或确认面板处理审批。下文的可选 AppCard 原型绕过应用 peer broker,直接访问共享内核服务。完整说明,包括代码路径以及哪些已在 `main` 上、哪些还在规划中:[docs/architecture.zh-CN.md](docs/architecture.zh-CN.md);相关决策:[ADR 0004(英文)](docs/adr/0004-native-apps-hosting-and-peers.md)。 ### 进程与连接 @@ -83,16 +83,19 @@ flowchart LR ### 系统 Agent 与应用 Agent -**系统 Agent** 是 `_main` profile 上的内核会话 `_main:api:octosense#system`(`crates/kernel/src/network.rs`)。它拥有并监督所有应用 Agent。用户在 Shell 的**助手面板**(即系统对话,`crates/shell/src/system_chat/`:Dock 上的 Assistant 图标、手机主屏的 Assistant 磁贴或 F8;桌面端是左侧一个中等大小、可移动、可调整大小并渲染 Markdown 的面板,手机上是全屏)或已配对的 Talk to Octos 客户端中与它对话。它的内核工具恰好是 `SYSTEM_AGENT_TOOLS`(`crates/kernel/src/system_tools.rs`):用于监督应用 Agent 的 `peer_send_input`、`peer_gather`、`peer_list` 和 `peer_respond`,其工作区的文件工具,记忆,`ask_user_question`,媒体查看,`web_search`、`web_fetch` 和 `tool_search`。每次内核启动都用 octos 的 `session/tool_list/set` 设置这份列表,所以 octos 自带的 shell、spawn 一族和 `peer_close` 永远不会提供给它。系统对话还会在这个会话上注册宿主工具:`agents.list` 和 `agents.ask`(`crates/shell/src/agents.rs`:哪些应用有 Agent,以及某个 Agent 的首次使用面板),以及在 Setup › Assistant › Command execution 打开期间的 `terminal.run`。 +**系统 Agent** 是 `_main` profile 上的内核会话 `_main:api:octosense#system`(`crates/kernel/src/network.rs`)。它拥有并监督所有应用 Agent。用户在 Shell 的**助手面板**(即系统对话,`crates/shell/src/system_chat/`:Dock 上的 Assistant 图标、手机主屏的 Assistant 磁贴或 F8;桌面端是左侧一个中等大小、可移动、可调整大小并渲染 Markdown 的面板,手机上是全屏)或已配对的 Talk to Octos 客户端中与它对话。它的内核工具恰好是 `SYSTEM_AGENT_TOOLS`(`crates/kernel/src/system_tools.rs`):用于监督应用 Agent 的 `peer_send_input`、`peer_gather`、`peer_list` 和 `peer_respond`,其工作区的文件工具,记忆,`ask_user_question`,媒体查看,`web_search`、`web_fetch` 和 `tool_search`。每次内核启动都用 octos 的 `session/tool_list/set` 设置这份列表,所以 octos 自带的 shell、spawn 一族和 `peer_close` 永远不会提供给它。系统对话还会在这个会话上注册宿主工具:`agents.list` 和 `agents.ask`(`crates/shell/src/agents.rs`:哪些应用有 Agent,以及某个 Agent 的首次使用面板与就绪等待),以及在 Setup › Assistant › Command execution 打开期间的 `terminal.run`。 **应用 Agent** 是每个(应用,账号)一个由宿主拥有的 octos peer([`crates/app-peers`](crates/app-peers/README.md))。`main` 上以下应用有 Agent(`crates/shell/src/apps.rs`,`agent_apps`): | 应用 | 声明方式 | 它的工具(由谁执行) | 它放到 glance 屏幕上的内容 | | --- | --- | --- | --- | | Rinx(原生) | `native-apps.json` 的 `agent.octos`(四个 `octos.*` 服务)和 `agent.generic_tools` | 其列表中的 octos 通用工具;它自己的助手界面 | – | -| 新闻(`os.news`) | `apps/news/bundle/tools.json`、manifest 中的 `agent` 块 | `news.list`、`news.read`(`news` 宿主服务) | – | +| 新闻(`os.news`) | `apps/news/bundle/tools.json`、manifest 中的 `agent` 块 | `news.list`、`news.read`、`news.notify`(`news` 宿主服务与 Shell 通知回调) | 通知卡片与通知 | | 邮件(`os.mail`) | `apps/mail/bundle/tools.json`、manifest 中的 `agent` 块和 `glance` | `mail.notify`(`mail` 宿主服务) | 一张通知卡片,并发出一条通知 | -| 日历(`os.calendar`,仅桌面端) | `apps/calendar/bundle/tools.json`、manifest 中的 `agent` 块和 `glance` | `calendar.events`、`calendar.add_event`、`calendar.remove_event`(破坏性操作:由用户批准)、`calendar.notify`、`calendar.agenda`(`calendar` 宿主服务) | 一张日程卡片或议程卡片,并发出一条通知 | +| 日历(`os.calendar`,仅桌面端) | `apps/calendar/bundle/tools.json`、manifest 中的 `agent` 块和 `glance` | `calendar.events`、`calendar.add_event`、`calendar.remove_event`(破坏性操作:进入审批路由)、`calendar.notify`、`calendar.agenda`(`calendar` 宿主服务) | 一张日程卡片或议程卡片,并发出一条通知 | +| Photos、Maps、YouTube;手机上的 Camera | 各自包内的 `tools.json`、`agent` 块与 `glance` | 各应用的 `.notify`(Shell `NoticeService`) | 通知卡片与通知 | + +AI providers 没有应用 Agent。 脚本应用在以下情况下拥有 Agent:manifest 声明了 `octos.*` 名称或 `agent` 块(`"tools": ["ask_user_question"]` 列出它可以使用的内核工具),或者应用包附带 `tools.json`(每个工具名为 `.`,带 schema、`risk`、`confirm` 和 `shareable`)。它的 peer 是 `card.<应用 id>`。用户只需在首次使用面板上允许一次(从 Shell 的 “Ask ” 面板、应用自己的 `octos` 调用,或系统 Agent 的 `agents.ask` 打开)。此后 Shell 在启动时就准备好这个 peer 并注册应用的工具,所以系统 Agent 的 `peer_list` 能看到它。在 Unix 上,已获同意且有可用 workspace 的应用 Agent 还能用宿主只读工具 `files.list`、`files.read` 和 `files.search` 读取账号文件夹;这些工具不会暴露所有宿主服务数据库。手机默认构建 `toolbox-peers`,因此在手机上,manifest 申请了 `research` 或 `crawl` 的应用 Agent 还会得到系统工具箱的工具;目前还没有应用申请。`AGENT.md`、技能和触发器([ADR 0002(英文)](docs/adr/0002-event-driven-app-agents.md))尚未实现:应用 Agent 只在系统 Agent、用户或卡片请求时运行。 @@ -130,7 +133,7 @@ sequenceDiagram -- 模型从不编写卡片代码:`mail.notify`、`calendar.notify` 和 `calendar.agenda` 填充应用宿主服务自带的固定 L0 卡片(`apps/mail/host-service/resources/notice.card`、`apps/calendar/host-service/resources/*.card`),并以该应用的身份发布。 +- 通知工具经 `glance_notice.rs` 填充 `crates/shell/resources/glance/notice.card`;Mail 和 News 的宿主服务回调委派到这里。Calendar 的事件与议程模板位于 `apps/calendar/host-service/resources/`。这些工具接收内容,以应用身份发布固定 L0 模板。 - `mail.notify` 和 `calendar.add_event` 是 `act` 工具,运行时不弹面板;octos 只对破坏性和对外的工具请求审批,这些审批交给 Shell 的审批路由([见下文](#一次带审批的工具调用))。 ### 一个应用 Agent,两条通道 @@ -229,7 +232,7 @@ sequenceDiagram - **工具调用**:octos 把 `peer/tool/call` 发给 Shell 的中转(`crates/shell/src/host_tools/`)。中转按(拥有工具的应用,工具)和调用方检查授权,按工具的 schema 检查参数,检查调用方的预算,再把调用路由到拥有工具的应用的执行器:进程内模块的执行器、脚本应用的宿主服务、进程应用的 peer link,或 AI bus 上 Terminal 的 `run`。 -- **审批**交给审批路由(`crates/shell/src/approvals/`):先看开发者模式,再看针对(拥有工具的应用,工具)的常设规则,否则弹出 Shell 绘制的面板。`confirm: app` 的工具在拥有它的应用自己的面板上确认,面板显示调用方。只有用户能批准;系统 Agent 永远不能。 +- **审批**交给 `crates/shell/src/approvals/`:外部客户端保留自己的提示;开发者模式批准覆盖应用的调用;`confirm: app` 使用所属应用注册的确认面板;必须现场决定的请求跳过规则;随后常设规则可决定符合条件的调用,其余由 Shell 面板询问用户。系统 Agent 无法批准。[导读](docs/architecture-walkthrough.zh-CN.md#审批顺序)列出完整顺序、时限与审计行为。 - **时限与停止**([#167](https://github.com/OctoSense-org/OctoSense/pull/167)):Shell 为应用 peer 持有的审批或提问在 10 分钟后过期(`OCTOSENSE_PROMPT_DEADLINE_SECS`):审批路由拒绝它,提问被婉拒,两者都保持显示为 "Expired: no answer in 10 min"。如果 30 秒后这一轮仍在运行,代理会中断它,好让下一轮开始。面板上的 “Stop 's agent” 会结束两条通道上正在运行的回合,包括用户的和系统 Agent 的;“Ask ” 面板的“停止”只结束用户自己的回合([见上文](#直接与应用的-agent-对话))。 - **外部客户端的提示**留在客户端:Shell 不回答、也不让 Talk to Octos 客户端各轮的审批过期(octos#2624)。 @@ -277,7 +280,7 @@ Shell 只有一份,位于 `crates/shell`([ADR 0001(英文)](docs/adr/000 ## AI 服务(octos) -每个 Shell 运行一个 [octos](https://github.com/octos-org/octos) Agent 内核,首次使用时启动:Android 上是 APK 中的 `liboctos.so`,OpenHarmony 上在进程内运行,桌面端运行 `OCTOS_APP_CORE_BIN` 指定的二进制,iOS 上没有。用户在系统应用 **AI providers** 中、在宿主面板上选择模型并输入密钥;密钥保存在平台的密钥存储中,永远不会到达应用。[`crates/ai-host`](crates/ai-host/README.md) 是两个 Shell 的统一入口,[`crates/app-peers`](crates/app-peers/README.md) 为每个获授权的原生应用分配自己的 octos peer(私有的上下文、工作区和记忆 `app//acct-`),归 Shell 的系统 Agent 所有。peer 的工具审批只能由用户在该应用中回答,系统 Agent 无法代答。 +每个 Shell 运行一个 [octos](https://github.com/octos-org/octos) Agent 内核,首次使用时启动:Android 上是 APK 中的 `liboctos.so`,OpenHarmony 上在进程内运行,桌面端运行 `OCTOS_APP_CORE_BIN` 指定的二进制,iOS 上没有。用户在系统应用 **AI providers** 中、在宿主面板上选择模型并输入密钥;密钥保存在平台的密钥存储中,永远不会到达应用。[`crates/ai-host`](crates/ai-host/README.md) 是两个 Shell 的统一入口,[`crates/app-peers`](crates/app-peers/README.md) 为每个获授权的原生应用分配自己的 octos peer(私有的上下文、工作区和记忆 `app//acct-`),归 Shell 的系统 Agent 所有。Peer 工具审批经 Shell 路由,由开发者模式、符合条件的常设规则,或用户在所属应用/Shell 确认面板上决定。系统 Agent 无法代答。 目前可用的:原生模块(Rinx)使用自己的 peer;AppCard(需主动开启)直接使用内核。隔离运行的脚本应用,无论系统应用还是商店应用,在托管了内核的 Shell 中通过 `octos` 宿主服务使用助手:每个应用有自己的、由宿主拥有的 peer(`card.<应用 id>`),它的工具审批和其他应用 Agent 一样交给 Shell 的审批面板([#155](https://github.com/OctoSense-org/OctoSense/pull/155))。`llm` 服务只为 `os.*` 应用管理提供方。应用自己的 Agent(`tools.json`、`AGENT.md`、skills、触发器、glance 卡片)见 [ADR 0002](docs/adr/0002-event-driven-app-agents.md);自 [#160](https://github.com/OctoSense-org/OctoSense/pull/160) 起,应用 `tools.json` 中由宿主服务实现的工具已通过 Shell relay 提供给其 Agent。标为 `implemented_by: "app"` 的工具仍缺少 Card runner 执行器;声明不等于实现。 diff --git a/apps/AGENTS.md b/apps/AGENTS.md index 9d301216..a8c7adab 100644 --- a/apps/AGENTS.md +++ b/apps/AGENTS.md @@ -36,18 +36,20 @@ app's own agent and `tools.json`, the system toolbox, `glance.publish` and `cargo test --locked -p octosense-mail-service`. Calendar's and News's: `apps/calendar/host-service`, `apps/news/host-service`, and `cargo test --locked -p octosense-calendar-service -p octosense-news-service`. -- An app's agent (News, Mail, Calendar) is declared by its manifest's - `agent` block and `bundle/tools.json`; each tool runs on the app's host - service (`implemented_by: "host-service"`), so a new tool is a new - host-service method plus its `tools.json` entry, with schemas that match - what the method answers (octos needs an object `output_schema`). Give a - tool the smallest `risk` that is true: `destructive` and outward tools get - the person's approval, `act` ones do not. A tool that shows something on - the glance screen fills a fixed L0 card the host service ships - (`resources/*.card`) and publishes it through the publisher the shell - installs (`on_publish_card`); never let the model write card code. The - app needs `glance` in its manifest. See the README's - [App agents](README.md#app-agents). +- Declare an app's agent in its manifest and `bundle/tools.json`. Keep the + input/output schemas consistent with the executor (octos requires an object + output schema), and select the actual risk, sharing and confirmation policy. + Add the implementation before adding a tool declaration; `implemented_by: + "app"` still has no Card runner executor. +- For a notification tool, follow `../crates/shell/src/glance_notice.rs`. + Mail/News install `on_notify` callbacks; the shell's `NoticeService` serves + Photos, Maps, YouTube and Camera. The fixed notice template lives in + `../crates/shell/resources/glance/notice.card`; Calendar keeps its own event + and agenda templates. Grant `glance` in the manifest and publish as the app. +- For richer app-owned cards, use `glance.publish` with either L0 `source` and + optional `data`, or a Splash `script`. Preserve app attribution, policy and + the distinction between app UI actions and agent tool calls. See + [App agents](README.md#app-agents) and the shell's glance tests. - There are no pins to bump: both shells pack `apps/` from the same commit (`desktop/system-apps.json`, `phone/system-apps.json`), so one pull request carries a change to every shell. App Hub, octos and the runtime are pinned @@ -108,19 +110,20 @@ are in [appcard/AGENTS.md](appcard/AGENTS.md); in short: - CI for it is the `apps` job of `.github/workflows/apps.yml`, which runs on changes under `apps/`, `crates/` and the workspace files. -## Architecture review and data access +## Changing tools and data access -Use the [product walkthrough](../desktop/docs/code-walkthrough.md) and -[agent walkthrough](../docs/architecture-walkthrough.md) when changing docs. -Keep host-service API methods, declared agent tools and agent-workspace files -separate. Mail currently declares only `mail.notify` in `bundle/tools.json`; -its UI service methods do not automatically become tools. Calendar's script -window is an instruction screen; the agent calls its Rust service for events. -News fetch timers do not currently trigger LLM turns. State these limits rather -than documenting intended behavior as shipped. +Trace each tool from `bundle/tools.json` through +`../crates/shell/src/host_tools/script_apps.rs` to its executor. Test schemas, +caller identity, approval behavior and results at that boundary. Keep UI API +methods separate from the tools actually declared for the agent: Mail currently +exposes only `mail.notify`; News exposes list/read/notify; Photos, Maps, YouTube +and Camera expose notify only. AI providers declares no app agent. -App Hub's Card runner and the optional AppCard assistant are different modules. -AppCard's historical personal-data mailbox reader is not the current Mail store. -Keep English/Chinese README changes paired and mark unrun launch/device recipes -as unverified. Documentation-only changes need link/source checks, not new -implementation-mirroring tests. +Use the [product walkthrough](../desktop/docs/code-walkthrough.md) for the data +and notice paths. For a cross-app tool, update the owner's shareable declaration, +requesting app's grant and App Hub admission offer together. Keep credentials in +the host service; expose business data through a narrow method or tool. + +Update both README languages when declarations, storage or runtime support +change. Add agent scheduling claims only when the trigger dispatcher exists; +News's fetch timer currently collects data without starting an LLM turn. diff --git a/apps/README.md b/apps/README.md index 6ab945d9..8ba252d1 100644 --- a/apps/README.md +++ b/apps/README.md @@ -2,9 +2,9 @@ English | [简体中文](README.zh-CN.md) -**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, real app data and Android platform boundaries; it marks unrun recipes explicitly. +**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, app data and Android platform boundaries. -> **Where this fits.** The system apps are script apps in App Hub's Card runner. They never talk to the octos kernel. News, Mail and Calendar have an agent (one host-owned octos peer per app and account, `card.`), declared by their manifest's `agent` block and `tools.json`; the shell drives it for the system agent, the shell's "Ask " panel and a card's in-card chat, and an app could also reach it with `host.request("octos.*")` (none of them does). The agent's calls to the app's tools come back through the shell's relay and approval router and run on the app's host service; Mail's and Calendar's tools put cards on the glance screen ([App agents](#app-agents)). An app's glance cards run under the app's own policy, and what the person does on them is the app's own action, not an agent tool call. Diagrams of the processes, an app agent's two lanes and a tool call with its approval: [How it fits together](../README.md#how-it-fits-together); the details: [docs/architecture.md](../docs/architecture.md) and [ADR 0004](../docs/adr/0004-native-apps-hosting-and-peers.md). +> **Where this fits.** System apps run in App Hub's Card runner. News, Mail, Calendar, Photos, Maps, YouTube and Camera declare app agents; AI providers configures the host and declares none. The shell gives each enabled app/account its own peer and drives its conversations for the system agent, the “Ask ” panel and in-card chat. Declared tools pass through the shell's relay and approval router to a host service; the shell's shared notice service handles apps that only expose `.notify`. See [App agents](#app-agents) for the exact tools and [architecture](../docs/architecture.md) for the two lanes and trust boundaries. Glance accepts L0 and Splash cards under the publishing app's policy. The first-party apps that ship with [OctoSense](https://github.com/OctoSense-org), the agent shell on top of your operating system, and the host services behind @@ -12,9 +12,8 @@ them. They live in `apps/` of the [OctoSense repository](../README.md); until 2026-09-27 they were the OctoSense-System-Apps repository (archived). - **News, Photos, Maps, Camera, Mail, Calendar, AI providers and YouTube** are *contained script apps*. Each is - an OctoScript (Splash) program in a `bundle/`, run by App Hub's Card runner - in its own isolate, under exactly the permissions its `manifest.json` asks - for. That is the same containment a store app gets. They are also worked + a Makepad Script/Splash program in a `bundle/`, run by App Hub's Card runner + in its own isolate, under the permissions admitted from its `manifest.json`. That is the same containment a store app gets. They are also worked examples of the app shape any developer publishes through the App Hub. - **Mail's host service** (`mail/host-service`) is the Rust half of Mail: IMAP/POP3/SMTP, the account store and the sign-in sheet, run by the shell. @@ -26,14 +25,15 @@ them. They live in `apps/` of the [OctoSense repository](../README.md); until which put an event or agenda card on the glance screen. Calendar is a desktop system app (`desktop/system-apps.json`). - **News's host service** (`news/host-service`) collects News's stories on a - timer, with no model, and runs News's agent's `news.list` and `news.read`. + timer, with no model, and runs News's agent tools `news.list`, `news.read` + and `news.notify` (the shell draws the notice). - **The `llm` host service** (`ai-providers/host-service`) is the Rust half of AI providers: the assistant's LLM providers over octos's model catalog, keys in the platform secret store, Test connection, and moving providers between devices by a PIN-protected `OCTOS1E` QR (camera, image or paste). Keys are typed and QRs drawn only on the host's own sheets; the app sees masked status. -- **AppCard** (`appcard`) is the one native app: the "Ask anything" +- **AppCard** (`appcard`) is an optional native app: the "Ask anything" assistant, a Rust module (`octos-app`) that the shells link in-process and that runs on the shell's octos kernel. It is **opt-in**: both shells link it only with `--features app-appcard`, and it is not shipped by default. @@ -68,12 +68,12 @@ OctoScript-App-Design-Flow: | App | Id | What it does | Capabilities (manifest) | Network hosts (manifest) | Host services | | --- | --- | --- | --- | --- | --- | | [News](news/bundle) | `os.news` | Hacker News, TechMeme and Google News feeds in tabs (Today, HN, TechMeme, Google, Saved), with a reader for stories | `storage`, `net`, `images`, `web`, `news`, `glance` | `hn.algolia.com`, `www.techmeme.com`, `news.google.com`, `api.gdeltproject.org`, `feeds.bbci.co.uk`, `feeds.npr.org`, `www.theguardian.com`, `feeds.arstechnica.com` | [`news`](news/host-service) | -| [Photos](photos/bundle) | `os.photos` | A sample library: moments, albums, people, favorites, a grid with selection, a full-screen viewer | `storage`, `glance` | none | none (full-size files come from a shell asset mount, see below) | -| [Maps](maps/bundle) | `os.maps` | `MapView` map, place search, places, routes with a changeable start and up to two stops, and a drive mode with turn-by-turn and a 2D/3D view; starts at the device's GPS fix when there is one | `storage`, `net`, `location`, `glance` | `photon.komoot.io`, `router.project-osrm.org`, `overpass-api.de`, `overpass.kumi.systems`, `maps.mail.ru`, `overpass.openstreetmap.fr` | none | -| [Camera](camera/bundle) | `os.camera` (Home) | Photo and video over the runtime's `CameraPreview` widget, flash and zoom, a thumbnail of the last shot and a viewer | `storage`, `camera`, `microphone`, `library`, `glance` | none | none | +| [Photos](photos/bundle) | `os.photos` | A sample library: moments, albums, people, favorites, a grid with selection, a full-screen viewer | `storage`, `glance` | none | `photos.notify` via the shell notice service (full-size photos use the asset mount) | +| [Maps](maps/bundle) | `os.maps` | `MapView` map, place search, places, routes with a changeable start and up to two stops, and a drive mode with turn-by-turn and a 2D/3D view; starts at the device's GPS fix when there is one | `storage`, `net`, `location`, `glance` | `photon.komoot.io`, `router.project-osrm.org`, `overpass-api.de`, `overpass.kumi.systems`, `maps.mail.ru`, `overpass.openstreetmap.fr` | `maps.notify` via the shell notice service | +| [Camera](camera/bundle) | `os.camera` (Home) | Photo and video over the runtime's `CameraPreview` widget, flash and zoom, a thumbnail of the last shot and a viewer | `storage`, `camera`, `microphone`, `library`, `glance` | none | `camera.notify` via the shell notice service | | [Mail](mail/bundle) | `os.mail` | Accounts, folders, message list, reader (HTML rebuilt by the service) and composer; its agent puts notice cards on the glance screen (`mail.notify`) | `storage`, `mail`, `glance` | none (the service connects, not the app) | [`mail`](mail/host-service) | | [AI providers](ai-providers/bundle) | `os.ai-providers` | The assistant's LLM providers: a primary and fallbacks, each with a model pull-down from octos's catalog and Test connection; an add wizard (family, model, route, key, test); Show QR for phone and import by camera, image or paste | `storage`, `llm` | none (the service connects, not the app) | [`llm`](ai-providers/host-service) | -| [YouTube](youtube/bundle) | `os.youtube` | YouTube search (the runtime's keyless `sys.video`, which reads YouTube's own results page), result rows with thumbnails and LIVE or length badges, topic chips, playback of YouTube's mobile watch page in `WebReader`, and a history of what was played on this device | `storage`, `net`, `glance` | `www.youtube.com`, `m.youtube.com`, `i.ytimg.com` | none | +| [YouTube](youtube/bundle) | `os.youtube` | YouTube search (the runtime's keyless `sys.video`, which reads YouTube's own results page), result rows with thumbnails and LIVE or length badges, topic chips, playback of YouTube's mobile watch page in `WebReader`, and a history of what was played on this device | `storage`, `net`, `glance` | `www.youtube.com`, `m.youtube.com`, `i.ytimg.com` | `youtube.notify` via the shell notice service | | [Calendar](calendar/bundle) | `os.calendar` (desktop) | Its agent keeps the person's events and puts event and agenda cards on the glance screen; its own window cannot list the events yet (it needs an App Hub `calendar` capability) | `storage`, `glance` | none | [`calendar`](calendar/host-service) (for Calendar's agent only) | | [AppCard](appcard) | native, opt-in | The AppCard assistant: a routing brain picks or composes an app agent, which generates a live Splash or webview card. Shells link it only with `app-appcard`; not shipped by default | n/a (not a bundle) | n/a | the shell's octos kernel | @@ -109,10 +109,8 @@ screen. `net` reaches only the hosts the manifest lists. - **News**: runs in `card-host` during development, but not exercised end to end in the shell PRs' test runs (the test phone had no network). - **Mail**: verified with the demo mailbox on desktop and on the OnePlus 6. - Mail's and the `llm` host services use the one App Hub revision the root - `Cargo.toml` pins (`46d67e51`, main after OctoSense-App-Hub#15; #11 added - the `llm` capability, #14 the Matrix and Octos host-service capabilities), - the same one the shells link, so a build has one `octosense-appstore` and + Mail's and the `llm` host services use the App Hub revision selected by the root + `Cargo.toml`, shared with the shells, so a build has one `octosense-appstore` and one host-service registry. - **Script bundles have no CI.** [`apps.yml`](../.github/workflows/apps.yml) tests the host services, AppCard and the shell services, not the bundles. @@ -155,8 +153,10 @@ standalone launcher and ROM image). Each packaging: `octosense-calendar-service`, `octosense-news-service` and `octosense-llm-service` (workspace path dependencies) through the shell, [`crates/shell`](../crates/shell) (its `app-hub` feature), and registers them at startup (`crates/shell/src/apps.rs`, `register_host_services`): Mail with `register()` for real accounts, or `register_demo()` - when the shell's app config has `mail_demo: true`, and with the publisher - its `mail.notify` (like Calendar's cards) publishes through; `llm` with the octos + when the shell's app config has `mail_demo: true`. Mail and News install + `on_notify` callbacks to the shell's common notice renderer; Calendar + installs its card publisher. The shell registers `NoticeService` for + remaining system-app namespaces; `llm` with the octos kernel's core dir and the shell's QR scanner and image picker (see [the `llm` service](#the-llm-service)). App Hub is pinned once, in the root `Cargo.toml`, so there is one host-service registry. @@ -179,11 +179,12 @@ request. ``` /bundle/ a contained script app: manifest.json, main.splash, artwork photos/resources/ Photos' sample library, which Home mounts -mail/host-service/ octosense-mail-service, the `mail` host service (Rust); resources/notice.card +mail/host-service/ octosense-mail-service, the `mail` host service (Rust); notice callback to the shell mail/docs/ Mail's plans (the email action card) calendar/host-service/ octosense-calendar-service, the `calendar` host service; resources/event.card, agenda.card news/host-service/ octosense-news-service, the `news` host service (News's data service) -/bundle/tools.json an app agent's own tools (News, Mail, Calendar) +/bundle/tools.json app tools: News, Mail, Calendar, Photos, Maps, YouTube, Camera +../crates/shell/src/glance_notice.rs shared notice service; ../crates/shell/resources/glance/notice.card ai-providers/ the `llm` host service (host-service/) and octosense-llm-config (config/: octos's model catalog and provider registry, the profile merge, OCTOS1/OCTOS1E QR) reference/ the reference module @@ -376,7 +377,7 @@ and `mail.send` methods are not thereby available to its agent. The peer's workspace also does not mount Mail's host database or credential vault. Calendar is a working example of an agent reading/writing its app data through declared Rust tools; its script window currently only explains how to ask the agent. -See the [data-access walkthrough](../desktop/docs/code-walkthrough.md#4-follow-real-data-through-a-tool-not-through-the-model). +See the [data-access walkthrough](../desktop/docs/code-walkthrough.md#4-follow-a-tool-into-app-data-and-glance). - **Declaring one.** The manifest's `agent` block names the kernel tools the agent may use (`"tools": ["ask_user_question"]`; a dotted name there asks @@ -407,9 +408,10 @@ See the [data-access walkthrough](../desktop/docs/code-walkthrough.md#4-follow-r control opens the panel yet. See the root [README](../README.md#talking-to-an-apps-agent-yourself). - **Its tools run on the app's host service**, as the app, after the - shell's relay checked the grant, the schema and the budget. octos asks - for an approval only for destructive and outward tools (here - `calendar.remove_event`), which the person answers on a shell sheet. + shell's relay checked the grant, the schema and the budget. destructive and outward calls (here `calendar.remove_event`) enter the + approval router. It applies the person's standing rules, host or registered + app confirmation sheets, and user-enabled developer mode; decisions are + audited. See [Approvals](../docs/architecture.md#5-approvals). - **Cards.** `.notify {title, body, card_id?, priority?}` puts a notice on the glance screen, with a notification: one fixed L0 card for every app, which the shell ships @@ -433,7 +435,7 @@ See the [data-access walkthrough](../desktop/docs/code-walkthrough.md#4-follow-r account (the demo mailbox, below, will do). Mail's richer action card ([the plan](mail/docs/2026-10-01-email-action-card-plan.md)) is so far a demo with fake data: `OCTOSENSE_GLANCE_DEMO=mail` publishes it at - startup. **Unverified** here (run in #267's checks, not for this page). + startup. **Unverified recipe.** ## The octos kernel @@ -481,8 +483,7 @@ octos UI Protocol v1. kernel, a WebSocket or REST) and `octos-app-render` (streaming-markdown renderer). - **octos**: every octos crate comes from git `octos-org/octos` at the one - rev in the root `Cargo.toml` `[workspace.dependencies]` (today `ae230ce0`, - octos `main`), shared with `crates/kernel` and the shells. AppCard starts no kernel of its + rev in the root `Cargo.toml` `[workspace.dependencies]` (see that file for the selected revision), shared with `crates/kernel` and the shells. AppCard starts no kernel of its own: it connects to the shell's ([The octos kernel](#the-octos-kernel)). - **Makepad**: not vendored. Makepad, Octoscript and Octoscript-Makepad are the checkouts in `.sources/` at the repository root that `tools/setup.py` @@ -567,7 +568,7 @@ plus an entry in each shell's `system-apps.json`. | [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow) | how to design, build, check and publish an app | | [OctoScript](https://github.com/OctoSense-org/OctoScript), [OctoScript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad), [makepad](https://github.com/OctoSense-org/makepad) | the language and runtime | | [Rinx](https://github.com/hagency-org/Rinx) | Matrix chats and mini apps, a native module; reaches the assistant through `crates/app-peers` | -| [octos](https://github.com/octos-org/octos) | the agent kernel: run as a shell service by `crates/kernel`, configured by AI providers, used by AppCard and other consumers (one rev, `ae230ce0`) | +| [octos](https://github.com/octos-org/octos) | the agent kernel: run as a shell service by `crates/kernel`, configured by AI providers, used by AppCard and other consumers (one revision selected by the root `Cargo.toml`) | ## Contributing diff --git a/apps/README.zh-CN.md b/apps/README.zh-CN.md index 807ef512..461e189c 100644 --- a/apps/README.zh-CN.md +++ b/apps/README.zh-CN.md @@ -2,18 +2,18 @@ [English](README.md) | 简体中文 -**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、真实数据和 Android 平台边界,并明确标注未运行的配方。 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、应用数据和 Android 平台边界。 -> **在整个系统中的位置。**系统应用是运行在 App Hub 的 Card runner 中的脚本应用。它们从不直接与 octos 内核通信。新闻、邮件和日历有 Agent(每个应用、每个账号一个由宿主拥有的 octos peer,`card.<应用 id>`),由 manifest 的 `agent` 块和 `tools.json` 声明;Shell 替系统 Agent、Shell 的 “Ask ” 面板和卡片的卡内对话驱动它,应用自己也可以用 `host.request("octos.*")` 使用它(目前没有应用这样做)。Agent 对应用工具的调用经由 Shell 的中转和审批路由回到应用,在应用的宿主服务上运行;邮件和日历的工具会把卡片放到 glance 屏幕上([应用 Agent](#应用-agent))。应用的 glance 卡片在应用自己的策略下运行,用户在卡片上的操作是应用自己的操作,而不是 Agent 的工具调用。进程、应用 Agent 的两条通道以及一次带审批的工具调用的图示:[整体如何运作](../README.zh-CN.md#整体如何运作);详细说明:[docs/architecture.zh-CN.md](../docs/architecture.zh-CN.md) 和 [ADR 0004(英文)](../docs/adr/0004-native-apps-hosting-and-peers.md)。 +> **在整个系统中的位置。**系统应用在 App Hub 的 Card runner 中运行。新闻、邮件、日历、相册、地图、YouTube 和相机声明应用 Agent;AI providers 配置宿主,自身不声明 Agent。Shell 为每个启用的应用/账号提供 peer,替系统 Agent、“Ask ” 面板和卡内聊天驱动对话。声明的工具经过 Shell 的 relay 和审批路由进入宿主服务;只暴露 `.notify` 的应用由 Shell 共用通知服务处理。具体工具见[应用 Agent](#应用-agent),两条通道和信任边界见[架构](../docs/architecture.zh-CN.md)。Glance 接受 L0 和 Splash 卡片,按发布应用的策略运行。 [OctoSense](https://github.com/OctoSense-org/.github/blob/main/profile/README.zh-CN.md)(运行在操作系统之上的 Agent 交互 Shell)自带的第一方应用,以及它们背后的宿主服务。 它们位于 [OctoSense 仓库](../README.zh-CN.md)的 `apps/`;2026-09-27 之前它们是 OctoSense-System-Apps 仓库(已归档)。 - **新闻(News)、相册(Photos)、地图(Maps)、相机(Camera)、邮件(Mail)、日历(Calendar)、AI providers 和 YouTube** - 是*隔离运行的脚本应用*。每个应用都是 `bundle/` 里的一个 OctoScript(Splash) - 程序,由 App Hub 的 Card runner 在独立的 isolate 中运行,权限严格等于其 - `manifest.json` 所申请的内容,与商店应用受到的隔离完全相同。它们同时也是 + 是*隔离运行的脚本应用*。每个应用都是 `bundle/` 里的一个 Makepad Script/Splash + 程序,由 App Hub 的 Card runner 在独立的 isolate 中运行,权限由其 + `manifest.json` 经过准入后确定,与商店应用受到的隔离完全相同。它们同时也是 任何开发者通过 App Hub 发布的应用形态的完整示例。 - **邮件的宿主服务**(`mail/host-service`)是 Mail 的 Rust 部分: IMAP/POP3/SMTP、账户存储和登录面板,由 Shell 运行。应用拿到的是邮件, @@ -24,12 +24,12 @@ OctoSense-System-Apps 仓库(已归档)。 放到 glance 屏幕上的 `notify` 和 `agenda`。日历是桌面端的系统应用 (`desktop/system-apps.json`)。 - **新闻的宿主服务**(`news/host-service`)按定时器收集新闻条目,不使用模型,并运行新闻 - Agent 的 `news.list` 和 `news.read`。 + Agent 的 `news.list`、`news.read` 和 `news.notify`(通知由 Shell 绘制)。 - **`llm` 宿主服务**(`ai-providers/host-service`)是 AI providers 的 Rust 部分:基于 octos 模型目录的大模型服务商、存放在平台密钥库中的密钥、“测试连接”, 以及通过受 PIN 保护的 `OCTOS1E` 二维码在设备之间迁移服务商(相机、图片或粘贴)。 密钥只在宿主自己的面板上输入,二维码也只在那里显示;应用只能看到打码后的状态。 -- **AppCard**(`appcard`)是唯一的原生应用:“Ask anything”助手, +- **AppCard**(`appcard`)是可选的原生应用:“Ask anything”助手, 一个由 Shell 进程内链接的 Rust 模块(`octos-app`),运行在 Shell 的 octos 内核之上。它**需显式启用**:两个 Shell 只有在使用 `--features app-appcard` 时才链接它,默认不随产品发布。 @@ -60,12 +60,12 @@ OctoScript-App-Design-Flow 的 `AGENTS.md`,再读 `docs/QUICKSTART.md`), | 应用 | Id | 功能 | 权限(manifest) | 网络主机(manifest) | 宿主服务 | | --- | --- | --- | --- | --- | --- | | [News](news/bundle) | `os.news` | Hacker News、TechMeme 和 Google News 的订阅源,分标签页(Today、HN、TechMeme、Google、Saved),带文章阅读器 | `storage`、`net`、`images`、`web`、`news`、`glance` | `hn.algolia.com`、`www.techmeme.com`、`news.google.com`、`api.gdeltproject.org`、`feeds.bbci.co.uk`、`feeds.npr.org`、`www.theguardian.com`、`feeds.arstechnica.com` | [`news`](news/host-service) | -| [Photos](photos/bundle) | `os.photos` | 示例相册:回忆、相簿、人物、收藏、可多选的网格、全屏查看器 | `storage`、`glance` | 无 | 无(原图来自 Shell 的资源挂载,见下文) | -| [Maps](maps/bundle) | `os.maps` | `MapView` 地图、地点搜索、地点详情、可更改起点并最多添加两个途经点的路线,以及带逐向导航和 2D/3D 视图的驾驶模式;有 GPS 定位时从当前位置开始 | `storage`、`net`、`location`、`glance` | `photon.komoot.io`、`router.project-osrm.org`、`overpass-api.de`、`overpass.kumi.systems`、`maps.mail.ru`、`overpass.openstreetmap.fr` | 无 | -| [Camera](camera/bundle) | `os.camera`(Home) | 基于运行时 `CameraPreview` 控件的拍照和录像,闪光灯和变焦,最近一张的缩略图和查看器 | `storage`、`camera`、`microphone`、`library`、`glance` | 无 | 无 | +| [Photos](photos/bundle) | `os.photos` | 示例相册:回忆、相簿、人物、收藏、可多选的网格、全屏查看器 | `storage`、`glance` | 无 | Shell 通知服务的 `photos.notify`(原图使用资源挂载) | +| [Maps](maps/bundle) | `os.maps` | `MapView` 地图、地点搜索、地点详情、可更改起点并最多添加两个途经点的路线,以及带逐向导航和 2D/3D 视图的驾驶模式;有 GPS 定位时从当前位置开始 | `storage`、`net`、`location`、`glance` | `photon.komoot.io`、`router.project-osrm.org`、`overpass-api.de`、`overpass.kumi.systems`、`maps.mail.ru`、`overpass.openstreetmap.fr` | Shell 通知服务的 `maps.notify` | +| [Camera](camera/bundle) | `os.camera`(Home) | 基于运行时 `CameraPreview` 控件的拍照和录像,闪光灯和变焦,最近一张的缩略图和查看器 | `storage`、`camera`、`microphone`、`library`、`glance` | 无 | Shell 通知服务的 `camera.notify` | | [Mail](mail/bundle) | `os.mail` | 账户、文件夹、邮件列表、阅读(HTML 由服务重建)和写信;它的 Agent 把通知卡片放到 glance 屏幕上(`mail.notify`) | `storage`、`mail`、`glance` | 无(由服务联网,而不是应用) | [`mail`](mail/host-service) | | [AI providers](ai-providers/bundle) | `os.ai-providers` | 助手的大模型服务商:一个主用与若干备用,每项都有来自 octos 模型目录的型号下拉菜单和“测试连接”;添加向导(系列、型号、线路、密钥、测试);“为手机显示二维码”,以及通过相机、图片或粘贴导入 | `storage`、`llm` | 无(由服务联网,而不是应用) | [`llm`](ai-providers/host-service) | -| [YouTube](youtube/bundle) | `os.youtube` | YouTube 搜索(运行时无需密钥的 `sys.video`,读取 YouTube 自己的搜索结果页),带缩略图和直播或时长角标的结果列表、话题标签,在 `WebReader` 中播放 YouTube 移动版观看页,以及本机播放记录 | `storage`、`net`、`glance` | `www.youtube.com`、`m.youtube.com`、`i.ytimg.com` | 无 | +| [YouTube](youtube/bundle) | `os.youtube` | YouTube 搜索(运行时无需密钥的 `sys.video`,读取 YouTube 自己的搜索结果页),带缩略图和直播或时长角标的结果列表、话题标签,在 `WebReader` 中播放 YouTube 移动版观看页,以及本机播放记录 | `storage`、`net`、`glance` | `www.youtube.com`、`m.youtube.com`、`i.ytimg.com` | Shell 通知服务的 `youtube.notify` | | [Calendar](calendar/bundle) | `os.calendar`(桌面端) | 它的 Agent 保存用户的日程,并把日程卡片和议程卡片放到 glance 屏幕上;它自己的窗口还不能列出日程(需要 App Hub 提供 `calendar` 权限) | `storage`、`glance` | 无 | [`calendar`](calendar/host-service)(只供日历的 Agent 使用) | | [AppCard](appcard) | 原生,需显式启用 | AppCard 助手:路由大脑选择或组合一个应用 Agent,由它生成实时的 Splash 或 webview 卡片。Shell 只在启用 `app-appcard` 时链接它;默认不发布 | 不适用(不是 bundle) | 不适用 | Shell 的 octos 内核 | @@ -93,7 +93,7 @@ OctoScript-App-Design-Flow 的 `AGENTS.md`,再读 `docs/QUICKSTART.md`), - **News**:开发时在 `card-host` 中运行过,但在 Shell PR 的测试中没有 端到端验证(测试手机没有网络)。 - **Mail**:已在桌面和 OnePlus 6 上用演示邮箱验证。Mail 与 `llm` 两个宿主服务使用根目录 - `Cargo.toml` 固定的唯一 App Hub 版本(`46d67e51`,OctoSense-App-Hub#15 合并后的 main;#11 新增了 `llm` 能力,#14 新增了 Matrix 与 Octos 宿主服务能力),与 Shell 链接的版本相同, + `Cargo.toml` 选定的 App Hub 版本,与 Shell 共用, 因此一次构建中只有一份 `octosense-appstore` 和一个宿主服务注册表。 - **脚本 bundle 没有 CI。** [`apps.yml`](../.github/workflows/apps.yml) 测试宿主服务、AppCard 和 Shell 服务,不测试 bundle。 @@ -130,8 +130,9 @@ OctoScript-App-Design-Flow 的 `AGENTS.md`,再读 `docs/QUICKSTART.md`), `octosense-mail-service`、`octosense-calendar-service`、`octosense-news-service` 和 `octosense-llm-service`(workspace 内的 path 依赖),并在启动时注册 (`crates/shell/src/apps.rs` 的 `register_host_services`):Mail 服务在真实账户下用 - `register()`,Shell 的应用配置中 `mail_demo: true` 时用 `register_demo()`,并装上 - `mail.notify`(与日历的卡片一样)发布卡片所用的发布器;`llm` 服务使用 octos 内核的 core 目录以及 + `register()`,Shell 的应用配置中 `mail_demo: true` 时用 `register_demo()`。 + Mail 和 News 安装 `on_notify` 回调,调用 Shell 共用通知渲染器;Calendar 安装卡片发布器。 + Shell 为其余系统应用命名空间注册 `NoticeService`;`llm` 服务使用 octos 内核的 core 目录以及 Shell 的二维码扫描器和图片选择器(见 [`llm` 服务](#llm-服务))。App Hub 只在根目录 `Cargo.toml` 中固定一次,因此只有一个宿主服务注册表。 3. 通过统一入口 [`crates/ai-host`](../crates/ai-host/README.md)(`octosense-ai-host`) @@ -149,11 +150,12 @@ OctoScript-App-Design-Flow 的 `AGENTS.md`,再读 `docs/QUICKSTART.md`), ``` /bundle/ 隔离运行的脚本应用:manifest.json、main.splash、图片资源 photos/resources/ Home 挂载的 Photos 示例图库 -mail/host-service/ octosense-mail-service,`mail` 宿主服务(Rust);resources/notice.card +mail/host-service/ octosense-mail-service,`mail` 宿主服务(Rust);通知回调交给 Shell mail/docs/ 邮件的计划(邮件操作卡片) calendar/host-service/ octosense-calendar-service,`calendar` 宿主服务;resources/event.card、agenda.card news/host-service/ octosense-news-service,`news` 宿主服务(新闻的数据服务) -/bundle/tools.json 应用 Agent 自己的工具(新闻、邮件、日历) +/bundle/tools.json 新闻、邮件、日历、相册、地图、YouTube、相机的 Agent 工具 +../crates/shell/src/glance_notice.rs 共用通知服务;../crates/shell/resources/glance/notice.card ai-providers/ `llm` 宿主服务(host-service/)和 octosense-llm-config(config/: octos 模型目录与服务商注册表、profile 合并、OCTOS1/OCTOS1E 二维码) reference/ reference 模块 @@ -352,8 +354,9 @@ Agent 开放。Peer 的工作目录也不会挂载 Mail 的宿主数据库或凭 工具。面板的“停止”只停止用户自己的回合。手机上还没有打开这个面板的触控入口。详见根目录的 [README](../README.zh-CN.md#直接与应用的-agent-对话)。 - **它的工具在应用的宿主服务上运行**,以应用的身份运行,在此之前 Shell 的中转已检查授权、 - schema 和预算。octos 只对破坏性和对外的工具请求审批(这里是 `calendar.remove_event`), - 由用户在 Shell 的面板上回答。 + schema 和预算。破坏性和对外调用(这里是 `calendar.remove_event`)进入审批路由; + 路由应用用户的常设规则、宿主或已注册的应用确认面板,以及用户开启的开发者模式,并记录决定。 + 见[审批](../docs/architecture.zh-CN.md#5-审批)。 - **卡片。** `.notify {title, body, card_id?, priority?}` 以应用的名义在 glance 屏幕上 放一张通知卡片,并发出一条通知:所有应用共用 Shell 自带的一张固定 L0 卡片 ([`../crates/shell/resources/glance/notice.card`](../crates/shell/resources/glance/notice.card), @@ -367,8 +370,7 @@ Agent 开放。Peer 的工作目录也不会挂载 Mail 的宿主数据库或凭 - **试一试**(桌面端):打开助手(F8),请系统 Agent 让某个应用的 Agent(邮件、日历、新闻、照片、 地图或 YouTube)在 glance 屏幕上放一张卡片;在弹出的面板上允许该 Agent。邮件需要一个已登录的账户(下文的演示邮箱即可)。 邮件更完整的操作卡片([计划(英文)](mail/docs/2026-10-01-email-action-card-plan.md))目前只是 - 使用假数据的演示:`OCTOSENSE_GLANCE_DEMO=mail` 会在启动时发布它。**未验证**(在 #267 的检查中 - 运行过,没有为本页重新运行)。 + 使用假数据的演示:`OCTOSENSE_GLANCE_DEMO=mail` 会在启动时发布它。**未验证配方。** ## octos 内核 @@ -409,8 +411,7 @@ octos UI Protocol v1 与 octos 通信。 (经由 Shell 内核、WebSocket 或 REST 的 octos UI Protocol 客户端)和 `octos-app-render`(流式 markdown 渲染)。 - **octos**:所有 octos crate 都来自 git `octos-org/octos`,版本为根目录 - `Cargo.toml` 的 `[workspace.dependencies]` 中唯一的 rev(目前是 octos `main` 上的 - `ae230ce0`),与 `crates/kernel` 和 Shell 共用。AppCard 不再自己启动内核,而是连接 Shell 的内核 + `Cargo.toml` 的 `[workspace.dependencies]` 中唯一的 rev(具体版本见该文件),与 `crates/kernel` 和 Shell 共用。AppCard 不再自己启动内核,而是连接 Shell 的内核 (见 [octos 内核](#octos-内核))。 - **Makepad**:不内置。Makepad、Octoscript 和 Octoscript-Makepad 是仓库根目录下 `.sources/` 中由 `tools/setup.py` 准备的检出,版本由 `native-runtime.lock.json` @@ -485,7 +486,7 @@ Shell 的 `system-apps.json` 中加入它。 | [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow) | 如何设计、构建、检查和发布应用 | | [OctoScript](https://github.com/OctoSense-org/OctoScript)、[OctoScript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad)、[makepad](https://github.com/OctoSense-org/makepad) | 语言与运行时 | | [Rinx](https://github.com/hagency-org/Rinx) | Matrix 聊天与小程序,原生模块;通过 `crates/app-peers` 访问助手 | -| [octos](https://github.com/octos-org/octos) | Agent 内核:由 `crates/kernel` 作为 Shell 服务运行,由 AI providers 配置,供 AppCard 等使用方使用(只用一个版本 `ae230ce0`) | +| [octos](https://github.com/octos-org/octos) | Agent 内核:由 `crates/kernel` 作为 Shell 服务运行,由 AI providers 配置,供 AppCard 等使用方使用(统一使用根 `Cargo.toml` 选定的版本) | ## 参与贡献 diff --git a/apps/appcard/AGENTS.md b/apps/appcard/AGENTS.md index 7dee83e1..7320f21f 100644 --- a/apps/appcard/AGENTS.md +++ b/apps/appcard/AGENTS.md @@ -51,10 +51,12 @@ All paths below are relative to `apps/appcard/` unless they say otherwise. - Follow the Makepad `script_mod!` DSL conventions of the `.sources/makepad` checkout (`Name: value`, `name := Type{}`, `+:` merge). -## Current shell architecture +## Integrating with the shell -AppCard is opt-in (`app-appcard`) and separate from App Hub's `CARD_MODULE`, -the current system chat and the app-peer broker. Keep its router/composer and -legacy personal-data docs scoped to this app. Reference is also a native app; -do not describe AppCard as the repository's only native app. See the -[product walkthrough](../../desktop/docs/code-walkthrough.md). +Keep AppCard changes in its router/composer, transport/store/render crates or +`module/` adapter. Change the shared system chat and app-peer broker in +`../../crates/` when that is the target. Test the `app-appcard` feature explicitly; +default and `mobile-apps` builds leave it out. When changing personal-data +integration, verify the current host-service data format before adding an +importer. The [product walkthrough](../../desktop/docs/code-walkthrough.md) +shows the hosting and data boundaries. diff --git a/apps/appcard/README.md b/apps/appcard/README.md index 01b6f1b2..814c8799 100644 --- a/apps/appcard/README.md +++ b/apps/appcard/README.md @@ -48,9 +48,9 @@ docs/ Architecture, protocol, build and review notes. Every octos crate (`octos-core`, and on OpenHarmony `octos-cli` with the ~20 crates it pulls in) comes from **one** source: git `https://github.com/octos-org/octos.git` at the single rev in the repository's -root `Cargo.toml` `[workspace.dependencies]` (today `ae230ce0`, octos main), +root [`Cargo.toml`](../../Cargo.toml) `[workspace.dependencies]`, shared with `crates/kernel` and both shells. octos's OpenHarmony-safe `nix` -is patched in the root `[patch.crates-io]` (from octos `18fcd3f1`). There is +is patched in the root `[patch.crates-io]` at the revision recorded there. There is no octos submodule; check the graph keeps one octos with `cargo tree --locked -p octos-app -i octos-core --target all --depth 0`. diff --git a/apps/appcard/README.zh-CN.md b/apps/appcard/README.zh-CN.md index e94d2ad2..753d7477 100644 --- a/apps/appcard/README.zh-CN.md +++ b/apps/appcard/README.zh-CN.md @@ -43,9 +43,8 @@ docs/ 架构、协议、构建与评审笔记。 所有 octos crate(`octos-core`,以及 OpenHarmony 上的 `octos-cli` 和它引入的约 20 个 crate)都来自**同一个**来源:git `https://github.com/octos-org/octos.git`, -版本为仓库根目录 `Cargo.toml` 的 `[workspace.dependencies]` 中唯一的 rev(目前是 -octos main 上的 `ae230ce0`),与 `crates/kernel` 和两个 Shell 共用。octos 中适配 -OpenHarmony 的 `nix` 在根目录的 `[patch.crates-io]` 中 patch(来自 octos `18fcd3f1`)。 +版本为仓库根目录 [`Cargo.toml`](../../Cargo.toml) 的 `[workspace.dependencies]` 中唯一的 rev,与 `crates/kernel` 和两个 Shell 共用。octos 中适配 +OpenHarmony 的 `nix` 在根目录的 `[patch.crates-io]` 中按该处记录的版本 patch。 没有 octos submodule;可用 `cargo tree --locked -p octos-app -i octos-core --target all --depth 0` 检查依赖图中只有一份 octos。 diff --git a/crates/kernel/README.zh-CN.md b/crates/kernel/README.zh-CN.md index 376f0c9a..710405e0 100644 --- a/crates/kernel/README.zh-CN.md +++ b/crates/kernel/README.zh-CN.md @@ -193,4 +193,4 @@ CI:`.github/workflows/apps.yml`(`services` 任务测试本 crate;`apps` OpenHarmony 构建它的工作区还需要 `nix` 补丁(octos rev `18fcd3f1`,见根目录 `Cargo.toml` 的 `[patch.crates-io]`)。其他平台上,内核是用同一 rev 构建的独立二进制文件。 -源码阅读补充:Rinx mini app 的 request context 有自己的内核会话和记录,但不是另一个应用 peer。线程、runtime 与回合任务的对应关系见[代码导读](../../docs/architecture-walkthrough.zh-CN.md#10-映射到-rust线程和-tokio)。 +源码阅读补充:Rinx mini app 的 request context 有自己的内核会话和记录,但不是另一个应用 peer。线程、runtime 与回合任务的对应关系见[代码导读](../../docs/architecture-walkthrough.zh-CN.md#10-映射到-rust-的实际执行模型)。 diff --git a/crates/shell/src/host_tools/script_apps.rs b/crates/shell/src/host_tools/script_apps.rs index 53b1a3ee..61c293cc 100644 --- a/crates/shell/src/host_tools/script_apps.rs +++ b/crates/shell/src/host_tools/script_apps.rs @@ -199,7 +199,7 @@ impl ToolExecutor for HostServiceExecutor { return; } if !self.tools.contains(&call.name) { - reply.finish(ToolOutcome::error("app_tool_unavailable", format!("{} runs in the app's own script; open the app to use it", call.name))); + reply.finish(ToolOutcome::error("app_tool_unavailable", format!("{} declares a script implementation, but this host does not support script tool dispatch", call.name))); return; } let family = call.name.split('.').next().unwrap_or(""); diff --git a/desktop/AGENTS.md b/desktop/AGENTS.md index 8b099107..7aed45e6 100644 --- a/desktop/AGENTS.md +++ b/desktop/AGENTS.md @@ -1,18 +1,23 @@ # Working on the desktop product -The [repository rules](../AGENTS.md) apply. Read the -[product source walkthrough](docs/code-walkthrough.md) before changing startup -or documenting native/script app hosting. +Follow the [repository rules](../AGENTS.md). Use the +[product walkthrough](docs/code-walkthrough.md) to trace startup and hosting. -- `src/main.rs` is the entry point; shared UI and hosting belong in - `../crates/shell/`, not copies under this directory. -- Run desktop Cargo commands from the root or this directory. Home commands - must run from `../phone/` to pick up its Cargo environment. -- `--module` selects native hosting; startup launch can be requested with - `MAKEPAD_WM_TEST_APP`. Match Cargo features to `../native-apps.json`. -- App Hub's Card runner is not the optional AppCard assistant. A native module, - a child process, an app-agent peer and a Tokio task are different concepts. -- For code changes, use the desktop and shared-shell checks named in the root - instructions. For documentation changes, inspect referenced symbols and - relative links; mark commands not executed as unverified. Change both README - languages together. Use hidden windows for UI validation. +- Put shared window-manager, app-hosting and UI changes in `../crates/shell/`. + Keep `src/main.rs` as the desktop entry point; keep desktop catalogs, + resources and packaging scripts here. +- Change native app features, grants and per-platform hosting in + `../native-apps.json`, then regenerate with `python3 tools/native_apps.py` + from the root. Check the generated graph with + `python3 tools/native_apps.py --check`. +- Run desktop Cargo commands from the root or `desktop/`. Run Home commands + from `phone/` so Cargo loads its system-app selection. +- Use `MAKEPAD_WM_TEST_APP=` to launch a test app at startup and `--module + ` to select module hosting. Use hidden windows and the Makepad remote + control surface for UI checks. +- When changing process-agent integration, follow `peer_link` and test context + ownership, process death, cancellation and confirmation acknowledgements. + Grant `agent.octos` explicitly in the native manifest before expecting a peer. +- Run the root's desktop/shared-shell checks for code changes. Update both + README languages and the corresponding walkthrough when startup behavior, + feature defaults or tool grants change. diff --git a/desktop/README.md b/desktop/README.md index 2896cc73..e4d7c4cc 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -2,7 +2,7 @@ English | [简体中文](README.zh-CN.md) -**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, real app data and Android platform boundaries; it marks unrun recipes explicitly. +**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, app data and Android platform boundaries. > **Where this fits.** The desktop is one shell process with the octos kernel as its child (`OCTOS_APP_CORE_BIN`). App Hub, the Card runner with the script apps, and Rinx run in process; the Terminal runs as its own process, in an OS sandbox on macOS and Linux (not yet on Windows), attached over the shell's hub. On macOS that sandbox keeps `~/.cargo`, `~/.rustup` and the OctoSense checkout read-only, so run `cargo install`, `rustup update` and builds of OctoSense itself in another terminal. Diagrams of the processes, an app agent's two lanes and a tool call with its approval: [How it fits together](../README.md#how-it-fits-together); the details: [docs/architecture.md](../docs/architecture.md) and [ADR 0004](../docs/adr/0004-native-apps-hosting-and-peers.md). diff --git a/desktop/README.zh-CN.md b/desktop/README.zh-CN.md index 3a446e4f..10f4ba6e 100644 --- a/desktop/README.zh-CN.md +++ b/desktop/README.zh-CN.md @@ -2,7 +2,7 @@ [English](README.md) | 简体中文 -**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、真实数据和 Android 平台边界,并明确标注未运行的配方。 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、应用数据和 Android 平台边界。 [OctoSense](https://github.com/OctoSense-org)(运行在操作系统之上的 Agent 交互 Shell)的桌面端 Shell,也是 OctoSense 仓库中的桌面端打包(原为 OctoSense-Desktop 仓库)。它是一个 Makepad 窗口,这个窗口本身就是桌面:launcher、dock 和平铺窗格(tile)。系统应用和 App Hub 商店应用以隔离的脚本程序运行,受信任的原生模块在进程内运行,Makepad 开发者程序作为子进程运行。它获取应用的方式与手机 Shell [Home](../phone/README.zh-CN.md) 完全相同。环境准备、仓库结构和 CI 见[根目录 README](../README.zh-CN.md)。 diff --git a/desktop/docs/code-walkthrough.md b/desktop/docs/code-walkthrough.md index d72bebc8..43b69204 100644 --- a/desktop/docs/code-walkthrough.md +++ b/desktop/docs/code-walkthrough.md @@ -2,138 +2,133 @@ English | [简体中文](code-walkthrough.zh-CN.md) -This is a source-reading tutorial for a Rust developer who is new to OctoSense. -Paths below are relative to the repository root. The companion -[agent architecture walkthrough](../../docs/architecture-walkthrough.md) follows -the kernel, peers, tools and Tokio tasks in more detail. +Follow an app from its executable entry point through hosting, data access and +agent interaction. Paths below are relative to the repository root. The +[agent architecture walkthrough](../../docs/architecture-walkthrough.md) continues +into the kernel, peers, tool routing and Tokio tasks. -The launch recipes below are **unverified in this documentation review**: their -package names, features and entry points were checked against source, but no GUI, -Android APK, ROM image or device was launched. Existing dated validation records -remain separate evidence. Run setup as described in the root README before using -Cargo; reuse existing framework clones with the sources-hub configuration. +**Launch recipes: unverified.** Prepare dependencies with the root README's setup +instructions first; use its sources-hub configuration to reuse existing clones. -## 1. Start with the nouns +## 1. Locate the running components -| Name | What actually runs | +| Component | Entry point and responsibility | | --- | --- | -| Desktop | The `octosense` executable; a thin entry point for `octosense-shell`. | -| Home | The `octosense-home` executable/APK; the same shell plus built-in Settings and platform integration. | -| Native app | Rust implementing Makepad's `AppModule`, or a separate executable hosted through the window-manager protocol. | -| OctoScript app | An admitted `manifest.json` + `main.splash` bundle, interpreted inside App Hub's Card runner. | -| Host service | Rust code that performs a specific operation for an attributed app and returns data. It need not use a model. | -| App agent | A model-driven octos peer scoped to an app/account, with a workspace, sessions and explicitly granted tools. | -| System agent | The shell's assistant, with its own tool policy and delegation tools. | -| ROM privileged agent | An Android Java/Binder service for platform operations. It is a different component from the model-driven system agent. | - -A Rust `trait` describes an interface; `impl AppModule` supplies one implementation. -A `Widget` handles UI events and drawing. Neither implies a thread, an LLM nor a -Tokio task. Likewise, a Splash file can be a native widget description or a -contained app's program: the host and its policy determine the authority. -Here `main.splash` runs on Makepad Script/Splash. The separate Octoscript L0 -parser/checker and `.card` lowering path are not the parser for that program. -“OctoScript app” is the product name used by these guides, not a claim that -these two language implementations are identical. - -## 2. Run the smallest native example +| Desktop | `desktop/src/main.rs` starts `octosense`, a thin entry point for `octosense-shell`. | +| Home | `phone/src/main.rs` starts `octosense-home`, adding Settings and platform integration to the shared shell. | +| Native app | Rust implementing Makepad's `AppModule`, or an executable hosted through the window-manager protocol. | +| Contained script app | App Hub's Card runner admits `manifest.json` and runs `main.splash` in a restricted Makepad Script/Splash VM. | +| Host service | Rust performs operations for an attributed app and returns data. | +| App agent | An octos peer scoped to an app/account, with sessions, a workspace and granted tools. | +| System agent | The shell's assistant session, with tools for discovery, delegation and selected system operations. | +| ROM privileged agent | Android's Java/Binder platform service, `AgentPlatformService`. | + +Contained `main.splash` programs use Makepad Script/Splash. L0 `.card` files pass +through Octoscript's separate parser/checker and Makepad lowering path. Both +appear in this product; follow the loading path for the artifact you are editing. + +## 2. Run Reference and follow native hosting From the repository root, after setup: ```sh -# An ordinary standalone Reference window. +# Standalone Reference window. cargo run --locked -p octosense-reference -# Reference linked into the desktop and opened as a module. +# Reference linked into the desktop and opened at startup. MAKEPAD_WM_TEST_APP=reference cargo run --locked -p octosense --features app-reference -- --module reference -# The normal desktop product (App Hub, Rinx, Terminal, kernel integration). +# Standard desktop: App Hub, Rinx, Terminal and kernel integration. cargo run --locked --release -p octosense ``` -These are development recipes, **unverified here**. To inspect UI without taking -over the screen, add `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=8000` and use the -Makepad control endpoints documented by `/help`; end the run through `/quit`. +For hidden-window inspection, add `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=8000`, +use the Makepad control endpoints documented by `/help`, and exit through `/quit`. `--module` selects hosting; `MAKEPAD_WM_TEST_APP` requests startup launch. Read these files in order: 1. [`apps/reference/src/lib.rs`](../../apps/reference/src/lib.rs): - `ReferenceView` holds `count: usize`; `handle_event` receives button/text - actions and changes labels. `draw_walk` delegates drawing to the contained - `View`. This is ordinary UI state, with no agent involved. -2. The same file's `ReferenceModule`: `register` makes its widget type known to - the VM; `create` returns `InstanceParts` containing a root widget, a service - executor and shutdown callback. The executor says “Reference has no tools”. - A native app does not automatically acquire an agent. -3. [`native-apps.json`](../../native-apps.json): Reference's source, feature, - hosting, storage and empty agent grants. This manifest generates the native - app registry and Cargo feature blocks; do not edit the generated blocks. -4. [`desktop/src/main.rs`](../src/main.rs): imports the shell's `App` and calls + `ReferenceView` owns `count`; `handle_event` receives button/text actions and + changes labels; `draw_walk` delegates to the contained `View`. +2. In the same file, `ReferenceModule::register` registers its widget type. + `create` returns `InstanceParts`: the root widget, service executor and + shutdown callback. `ReferenceExecutor` exposes no tools. +3. [`native-apps.json`](../../native-apps.json) declares Reference's source, + feature, hosting, storage and empty agent grants. The generator uses it to + produce the native registry and Cargo feature blocks. +4. [`desktop/src/main.rs`](../src/main.rs) imports the shell's `App` and invokes `octosense_main!`. In [`crates/shell/src/lib.rs`](../../crates/shell/src/lib.rs), - that macro delegates to Makepad's `app_main!` and selects the package directory. -5. Follow `App::launch_app_with_args` in that shell file. It finds a registered - app, checks script-app identity/admission where applicable, prepares storage, - optionally focuses an existing window, then chooses module or process hosting. -6. [`crates/shell/src/module_host.rs`](../../crates/shell/src/module_host.rs), - `ModuleHost::create`: establishes an instance scope, storage namespace, reply - handles, viewport and VM, then builds the module. Agent services are injected - only when declared and granted by host policy. + the macro calls Makepad's `app_main!` and selects the package directory. +5. `App::launch_app_with_args` finds the registered app, checks script-app + identity/admission where needed, prepares storage, optionally focuses an + existing window, then selects module or process hosting. +6. [`ModuleHost::create`](../../crates/shell/src/module_host.rs) creates the + instance scope, storage namespace, reply handles, viewport and VM, then the + module. Host policy controls which declared agent services it receives. For process hosting, continue to -[`crates/shell/src/clients.rs`](../../crates/shell/src/clients.rs) and +[`clients.rs`](../../crates/shell/src/clients.rs) and [`crates/process-apps`](../../crates/process-apps). The shell starts a child, connects the window-manager protocol, forwards input and displays its surface. -That child process is independent of any octos peer. Terminal normally uses this -path on macOS/Windows and with Vulkan in a Linux Wayland session; its module -fallback and overrides are described in the [desktop README](../README.md). +Terminal normally uses this path on macOS/Windows and in a Vulkan-enabled Linux +Wayland session; see the [desktop README](../README.md) for module fallback and +overrides. + +A native app can also reach its agent over +[`peer_link`](../../crates/shell/src/peer_link/mod.rs). Process apps send an +`octos_peer` envelope over their existing authenticated hub socket. The shell +attributes frames to the launched app, checks its `agent.octos` grants and +consent, and connects requests to the same app-peer broker used by modules. +Module `OctosPeer` channels enter this link through `module_connected` and +`on_module_frame`. Tool outcomes and cancellations travel back through the link; +when a process dies, its contexts close and pending calls fail while the durable +peer remains. **No shipped process app currently requests an agent:** Terminal's +manifest exposes tools but has an empty `agent.octos` list. ## 3. Run and follow a script bundle -The normal desktop already contains the selected system bundles. Open News or -Calendar from the launcher. A standalone preview uses the App Hub repository's -`card-host`; from an App Hub checkout after its own setup: +The desktop packages selected system bundles; open News or Calendar from the +launcher. For standalone preview, run App Hub's `card-host` from an App Hub +checkout after following that repository's setup: ```sh -# Replace the example path with your OctoSense checkout. +# Replace the path with your OctoSense checkout. cargo run --locked --release -p octosense-card-host --bin card-host -- --bundle /path/to/OctoSense/apps/news/bundle --system ``` -This recipe is **unverified here**. `--system` admits the shipped `os.*` bundle; -it does not give the preview the shell's host services or agent UI. In particular, -Mail requires the shell's service. A source-backed desktop recipe is: +`--system` admits the shipped `os.*` bundle. Shell host services and agent UI +require the full shell. For example, run Mail's demo service from the OctoSense +root: ```sh MAKEPAD_APP_CONFIG='{"mail_demo":true}' cargo run --locked --release -p octosense ``` -The demo account uses password `demo`; its sends stay in the demo. New store apps -belong in OctoScript-App-Design-Flow, then App Hub's admission/publishing flow. -Use a local catalog to test the real shell installation path; see -[the desktop local-catalog recipe](../README.md#try-your-own-app-before-it-is-published). +The demo account uses password `demo`; sends stay in the demo. Develop new store +apps in OctoScript-App-Design-Flow and use App Hub's admission/publishing flow. +The [local-catalog recipe](../README.md#try-your-own-app-before-it-is-published) +tests installation into the shell before publication. -Read [`desktop/system-apps.json`](../system-apps.json) and -[`phone/system-apps.json`](../../phone/system-apps.json): these select bundles -from `apps/`. Follow [`crates/shell/src/apps.rs`](../../crates/shell/src/apps.rs) -for launcher entries, `agent_apps` and `register_host_services`. The linked App -Hub `CARD_MODULE` is a native host for those interpreted programs. It is distinct -from the opt-in AppCard assistant module. +[`desktop/system-apps.json`](../system-apps.json) and +[`phone/system-apps.json`](../../phone/system-apps.json) select bundles from +`apps/`. Follow [`apps.rs`](../../crates/shell/src/apps.rs) for launcher entries, +`agent_apps` and `register_host_services`. App Hub's native `CARD_MODULE` hosts +these interpreted programs. The optional AppCard assistant has its own module. -An app's manifest requests capabilities; admission converts those requests into -a policy. A script's `host.request(...)` is checked under that app's identity. -It is not arbitrary Rust execution and not automatically an LLM tool call. -App Hub's `crates/appstore/src/services.rs` defines `HostService`, `ServiceCall` -and replies. `ServiceCall` carries the app identity and host directory; a service -can check both the method and caller before doing work. +Admission resolves manifest capability requests into policy. A script's +`host.request(...)` runs under that app's identity. App Hub's +`crates/appstore/src/services.rs` defines `HostService`, `ServiceCall` and replies; +the call supplies an app identity and host directory for the service to check. +Only explicitly declared agent tools make corresponding operations available +to a model. -## 4. Follow real data through a tool, not through the model +## 4. Follow a tool into app data and Glance -Start with [`apps/calendar/bundle/tools.json`](../../apps/calendar/bundle/tools.json) -and [`apps/calendar/host-service/src/lib.rs`](../../apps/calendar/host-service/src/lib.rs). -The JSON declares tools and schemas; it contains no implementation. The Rust -`CalendarService` implements the host-service interface; `handle` dispatches -methods, while `load`/`save` own `/calendar/events.json`. - -For “add an event”, the path is: +Start with [`Calendar's tools.json`](../../apps/calendar/bundle/tools.json) and +[`CalendarService`](../../apps/calendar/host-service/src/lib.rs). JSON declares +schemas and policy; Rust `handle` dispatches methods and `load`/`save` manage +`/calendar/events.json`. ```mermaid sequenceDiagram @@ -152,130 +147,159 @@ sequenceDiagram A-->>H: Answer in the requesting conversation ``` -Read [`crates/shell/src/host_tools/script_apps.rs`](../../crates/shell/src/host_tools/script_apps.rs) -for tool loading and `HostServiceExecutor`, then `host_tools/relay.rs` for -authorization. `calendar.remove_event` is destructive and needs the configured -host confirmation. `calendar.notify`/`agenda` fill fixed `.card` resources and -call the publisher installed by `register_host_services`; the shell checks the -app's `glance` grant. The model supplies arguments, not executable card code. +Read [`script_apps.rs`](../../crates/shell/src/host_tools/script_apps.rs) for tool +loading and `HostServiceExecutor`, then +[`relay.rs`](../../crates/shell/src/host_tools/relay.rs) for authorization. +`calendar.remove_event` requires destructive-action approval. The shell's +[approval router](../../crates/shell/src/approvals/mod.rs) applies the person's +standing rules or presents a confirmation; registered `confirm: app` tools use +the owning app's sheet. Developer mode supplies a separate user-enabled override. +The router records decisions in its owner-only audit log. These paths determine +whether a tool runs; the model supplies only the call and arguments. -Do not confuse these three stores/interfaces: +The shipped declarations provide these operations: -| Boundary | Actual access | +| Agent-enabled app | Tools and implementation | +| --- | --- | +| News | `news.list`, `news.read` and `news.notify`; News's host service handles them and hands notices to the shell. | +| Mail | `mail.notify` only; Mail's service calls the shell's `on_notify` hook. UI operations such as `mail.list`, `mail.message` and `mail.send` have no corresponding agent declarations. | +| Calendar | `calendar.events`, `add_event`, `remove_event`, `notify`, `agenda`; its Rust service owns events and event/agenda card templates. | +| Photos, Maps, YouTube, Camera | `.notify` only; the shell's `NoticeService` handles each application's namespace. Camera is packaged by Home. | + +AI providers configures the host and currently declares no app agent. Calendar's +script window explains how to ask its agent; its events are available through +the tools above while App Hub has no script `calendar` capability. + +Follow [`glance_notice.rs`](../../crates/shell/src/glance_notice.rs) and +[`resources/glance/notice.card`](../../crates/shell/resources/glance/notice.card) +for the shared notice. Mail and News keep their own services and install notice +callbacks; `serve_system_apps` adds a `NoticeService` only for namespaces without +a service. `publish_args` fills app name/icon, time, title and body, then +`glance::publish_for` checks the app's `glance` grant. The notice opens its app and +sets `notify: true`. Calendar keeps its own event and agenda card templates. + +The broader [`glance.publish`](../../crates/shell/src/glance.rs) API accepts either +L0 `source` with optional `data`, or a Splash `script` carrying its own values. +Both render under the publishing app's policy. `notify: true` queues a toast; +the host's `glance::dismiss` removes a card closed by the person. The fixed notice +tools above accept text arguments; the script-card API serves richer app-owned +surfaces. A person's action on such a surface uses the app's API permissions. + +The tests beside these implementations show the contracts directly: +`a_host_service_tool_runs_as_the_apps_own_request` in `script_apps.rs`, +`system_apps_without_a_service_of_their_own_get_the_notice_service` in +`glance_notice.rs`, and `a_script_card_is_admitted_as_it_is` in `glance.rs`. +They check attribution, namespace fallback and the script-card admission path. + +Keep the data boundaries visible when adding a tool: + +| Boundary | Access path | | --- | --- | -| Script storage | The app's storage capability and jail; only the runtime's allowed APIs. | -| Agent workspace | The peer's app/account directory; only explicitly granted file tools, confined by shell policy. It is not a mount of every host-service database. | -| Host-service database | Rust-owned data such as Calendar events, Mail cache and credentials, or News cache; accessed through explicitly exposed methods/tools. Secrets stay with host-owned sheets and vaults. | - -Current examples deliberately differ. News declares `news.list` and `news.read`. -Mail's **agent tool file declares only `mail.notify`**: the service's UI methods -`mail.list`, `mail.message` and `mail.send` are not thereby agent tools. Calendar's -window currently explains how to ask its agent; it does not list/edit events -through a script `calendar` capability, which App Hub does not expose. - -Cross-app access also needs explicit declarations: the requesting agent asks for -a dotted tool name in `agent.tools`; the owner must offer a shareable tool, and -the relay must grant and execute it under the right identities. App Hub admission -also checks `HostLimits.offered_tools`; arbitrary dotted names such as -`mail.send` are not offered by default, so editing `agent.tools` alone does -not make the bundle admissible. A writable -workspace or a chat message does not grant another app's files, credentials or -API. See the companion walkthrough for system-agent delegation and current -limits on reverse requests from an app agent to the system agent. - -## 5. Where a person talks to the app agent - -The shell draws an **Ask <app>** panel for agent-enabled apps. On desktop, -focus the app and use the bar, Shift+F8, or “Ask this app's agent” in the menu. -First-use consent precedes preparation of its peer. F8 opens the system agent; -`agents.ask` requests consent/preparation, then `peer_send_input` delegates work -and `peer_gather` retrieves the answer. A card's `sys.chat` can also address its app -agent. Phone touch navigation has no equivalent panel-opening control yet. - -Follow `crates/shell/src/app_chat/`, `crates/shell/src/system_chat/`, -`crates/shell/src/agents.rs`, `crates/ai-host/src/contained.rs` and -`crates/app-peers/`. The human conversation and system-agent conversation have -separate lanes/sessions on the app's peer; the panel's Stop interrupts the -human's turn. “One peer” does not mean “one shared transcript”, “one OS thread” -or “one Tokio task”. The Makepad event loop handles UI; broker/kernel work and -notifications cross their own channels. The companion walkthrough maps those -channels and kernel tasks to source symbols. - -The kernel must also be configured: `octos-core` links the integration but does -not manufacture a desktop `octos` executable or a provider credential. Supply a -compatible `OCTOS_APP_CORE_BIN`, configure AI providers and use the -[kernel guide](../../crates/kernel/README.md). Android packages bundle -`liboctos.so`; desktop and Android normally run a child kernel, while -OpenHarmony uses the in-process core. These are kernel hosting choices, separate -from whether the app UI is a module or child process. - -## 6. Home adds Settings around the shared shell - -Run Cargo **from `phone/`**, because its `.cargo/config.toml` selects the phone's -bundles. From that directory, the desktop preview recipe (**unverified here**) is: +| Script storage | Runtime storage APIs under the app's capability and jail. | +| Agent workspace | The peer's app/account folder through granted file tools and shell policy. | +| Host-service database | Explicit Rust methods/tools for Calendar events, Mail cache or News data. Credentials stay with host sheets and vaults. | + +For cross-app calls, the requester names a dotted tool in `agent.tools`; its +owner must declare it shareable and the relay must grant it. Admission also +checks `HostLimits.offered_tools`: names such as `mail.send` are absent from the +default offers. Add a complete declaration, admission offer and executor path +before documenting a usable integration. The +[agent walkthrough](../../docs/architecture-walkthrough.md) covers delegation +and requests for help from another agent. + +## 5. Follow a person's conversation + +On desktop, focus an agent-enabled app and open **Ask <app>** from the bar, +Shift+F8 or the menu. F8 opens the system agent. `agents.list` reports app agents; +`agents.ask` waits for first-use consent and peer preparation, then returns the +peer slug. The system agent sends the task with `peer_send_input` and gathers its +answer with `peer_gather`. A card's `sys.chat` can address its own app agent. +Phone touch navigation has no Ask-app panel-opening control yet. + +Follow [`app_chat/`](../../crates/shell/src/app_chat/mod.rs), +[`system_chat/`](../../crates/shell/src/system_chat/mod.rs), +[`agents.rs`](../../crates/shell/src/agents.rs), +[`contained.rs`](../../crates/ai-host/src/contained.rs) and +[`app-peers`](../../crates/app-peers/README.md). Human and system-agent work uses +separate sessions/lanes on the peer; the panel's Stop interrupts the human turn. +Makepad handles UI events, while broker/kernel channels carry requests and +notifications. The companion walkthrough maps these channels to Rust tasks. + +Configure a compatible desktop `OCTOS_APP_CORE_BIN` and a provider in AI providers; +`octos-core` enables the integration in the build. See the +[kernel guide](../../crates/kernel/README.md). Android bundles `liboctos.so` and +runs it as a child; OpenHarmony runs the core in-process. App UI hosting and +kernel hosting are selected independently. + +## 6. Follow Home's Settings and platform bridge + +Run Cargo **from `phone/`** so its `.cargo/config.toml` selects the phone bundles: ```sh cargo run --locked --release -p octosense-home --features mobile-only -# Add Reference/Sheets too; mobile-only and mobile-apps have different jobs. +# Also link Reference and Sheets. cargo run --locked --release -p octosense-home --features mobile-only,mobile-apps ``` [`phone/src/main.rs`](../../phone/src/main.rs) defines `App` with `#[deref] -shell: ShellApp` plus `SettingsRuntime`. Dereferencing lets its implementation -reach shell fields; it does not create another shell process. `install_ext` -registers the trusted Settings module. In `handle_event`, Home first handles -Settings startup/timing and entry intents, lets the shell process the event, -then consumes queued platform packets and Settings requests. Observe that -ordering when debugging a missing Settings update. - -Follow `phone/src/settings_app.rs`, `settings_script.rs` and -`settings_script_host_facade.rs`: Settings combines a script-owned controller/UI -with Rust host checks. Its privilege comes from the compiled trusted singleton, -not from a script declaring itself “settings”. `android_settings.rs` dispatches -observations/results by channel. A returned command result and a later observed -platform state are distinct; accepted work must not be displayed as confirmed -platform state prematurely. +shell: ShellApp` and `SettingsRuntime`. `install_ext` registers the trusted +Settings module. `handle_event` first handles Settings startup/timing and entry +intents, passes the event to the shell, then consumes queued platform packets +and Settings requests. If a Settings update goes missing, check this ordering +first. + +[`settings_app.rs`](../../phone/src/settings_app.rs), +[`settings_script.rs`](../../phone/src/settings_script.rs) and +[`settings_script_host_facade.rs`](../../phone/src/settings_script_host_facade.rs) +connect the script-owned controller/UI to Rust host checks. Privilege comes from +the compiled trusted singleton. [`android_settings.rs`](../../phone/src/android_settings.rs) +dispatches observations/results by channel. A command's accepted result and a +later observed platform state have separate handlers; the latter confirms what +the device currently does. On Android, continue into -`phone/resources/android/java/dev/makepad/octosense/MakepadAppExtension.java`, -the clients there, and `phone/android/contracts/`. The System Bridge's -`SystemBridgeService.java` uses Binder callbacks and caller checks. Ordinary -standalone Home has only available Android permissions/roles; installing Home -does not give it ROM privileges. Follow [Home's build instructions](../../phone/README.md#build-and-run) -for APK packaging; a desktop preview proves neither Binder nor device behavior. - -## 7. The ROM packages the platform, not another LLM peer - -Read [`rom/vendor/octosense/octosense.mk`](../../rom/vendor/octosense/octosense.mk) -and `Android.bp` for product inclusion, then -[`rom/scripts/build-home.py`](../../rom/scripts/build-home.py), `stage-home.py` -and `stage-forks.sh`. Build produces the Home/Bridge APK pair and receipt; -staging verifies and copies artifacts; the LineageOS build produces the image. -Installing, flashing and OTA delivery are separate operations. - -The privileged Android service lives in -`rom/vendor/octosense/agent/src/dev/makepad/octosense/agent/AgentPlatformService.java`. -Its `caller` checks Binder UID, allowed package identity and platform signature; -methods use platform backends and report capabilities/results. Its AIDL contract -is `IAgentPlatform.aidl`. It is a Java service with Android lifecycle and Binder -execution, not an octos model loop and not a Rust Tokio app-agent task. - -Home's `AgentPlatformClient` connects to that optional ROM service. The System -Bridge, Quickstep, SystemUI, Settings brokers and privileged agent are distinct -Android pieces, not a universal “system agent” API an arbitrary app can call. -Source checks cannot prove that a ROM boots or that its platform integration -works; image/device validation remains **unverified in this review**. - -## 8. Keep the older AppCard path separate - -`apps/appcard/module/src/lib.rs` adapts the optional AppCard assistant to -`AppModule`; `apps/appcard/app/app` implements its router/composer and generated -cards, with transport/store/render crates beside it. Enable it explicitly with -`--features app-appcard`; defaults and `mobile-apps` leave it out. - -AppCard's older routing/composition terminology is not the implementation of -every modern system/app agent. The current system chat, app-chat broker and -contained script agents work without enabling AppCard. Likewise its legacy -`personal-data` mailbox reader is not current Mail's host-service database API. -For learning native hosting, start with Reference; for shipped app-agent tools, -start with Calendar/News; read AppCard when working on that optional product. +[`MakepadAppExtension.java`](../../phone/resources/android/java/dev/makepad/octosense/MakepadAppExtension.java), +its clients and [`phone/android/contracts/`](../../phone/android/contracts). +The bridge's [`SystemBridgeService.java`](../../phone/android/system-bridge/src/main/java/dev/makepad/octosense/bridge/SystemBridgeService.java) +uses Binder callbacks and caller checks. Standalone Home operates within its +Android permissions/roles; the ROM supplies additional privileged components. +Follow [Home's build instructions](../../phone/README.md#build-and-run) for APK +packaging and the separate device-validation steps. + +## 7. Follow the ROM packaging and privileged service + +Read [`octosense.mk`](../../rom/vendor/octosense/octosense.mk) and +[`Android.bp`](../../rom/vendor/octosense/Android.bp) for product inclusion, +then [`build-home.py`](../../rom/scripts/build-home.py), +[`stage-home.py`](../../rom/scripts/stage-home.py) and +[`stage-forks.sh`](../../rom/scripts/stage-forks.sh). Building produces the +Home/Bridge APK pair and receipt; staging verifies and copies artifacts; the +LineageOS build produces the image. Installation, flashing and OTA delivery have +separate scripts and validation steps. + +[`AgentPlatformService.java`](../../rom/vendor/octosense/agent/src/dev/makepad/octosense/agent/AgentPlatformService.java) +checks Binder UID, allowed package identity and platform signature in `caller`. +Its [`IAgentPlatform.aidl`](../../rom/vendor/octosense/agent/src/dev/makepad/octosense/agent/IAgentPlatform.aidl) +methods invoke platform backends and return capabilities/results. Android owns +its service lifecycle and Binder execution; the LLM system conversation belongs +to the octos kernel described earlier. + +Home's `AgentPlatformClient` connects to this optional ROM service. System +Bridge, Quickstep, SystemUI and Settings brokers have their own Android roles +and permission boundaries. Use the ROM's +[validation instructions](../../rom/README.md#testing-and-validation) to check +boot, platform operations and update behavior on an assigned device. + +## 8. Follow the optional AppCard product + +[`apps/appcard/module/src/lib.rs`](../../apps/appcard/module/src/lib.rs) adapts +AppCard to `AppModule`; [`apps/appcard/app/app`](../../apps/appcard/app/app) +implements its router/composer and generated cards, alongside the +transport/store/render crates. Enable `--features app-appcard`; default builds +and `mobile-apps` leave it out. + +The shared shell implements system chat, app chat and contained-app peers +independently of AppCard. AppCard's legacy `personal-data` integration reads the +older native Mail format; current Mail owns its cache in a host service. Start +with Reference for native hosting, Calendar/News for app tools, and AppCard's +own docs when changing its routing and card-generation product. diff --git a/desktop/docs/code-walkthrough.zh-CN.md b/desktop/docs/code-walkthrough.zh-CN.md index 0bd0be22..62f1f727 100644 --- a/desktop/docs/code-walkthrough.zh-CN.md +++ b/desktop/docs/code-walkthrough.zh-CN.md @@ -2,80 +2,114 @@ [English](code-walkthrough.md) | 简体中文 -本文面向刚接触 OctoSense 的 Rust 开发者。文中的源码路径相对于仓库根目录。 -[Agent 架构导读](../../docs/architecture-walkthrough.zh-CN.md)进一步追踪内核、Peer、工具和 Tokio 任务。 +沿着可执行程序入口,追踪应用托管、数据访问和 Agent 交互。以下路径相对于仓库根目录。 +[Agent 架构导读](../../docs/architecture-walkthrough.zh-CN.md)继续介绍内核、peer、工具路由和 Tokio 任务。 -以下启动配方均为**本次文档审查未验证**:已核对源码中的包名、feature 和入口,但没有启动 GUI、构建 Android APK/ROM 或运行设备测试。已有的带日期验证记录是独立证据。运行 Cargo 前按根目录 README 准备依赖;已有框架克隆时通过 sources hub 复用。 +**启动配方:未验证。** 先按根目录 README 准备依赖;已有框架克隆时,通过其 sources hub 配置复用。 -## 1. 先理解几个名称 +## 1. 找到运行中的组件 -| 名称 | 实际运行的东西 | +| 组件 | 入口和职责 | | --- | --- | -| 桌面 | `octosense` 可执行程序,入口很薄,主体是 `octosense-shell`。 | -| Home | `octosense-home` 程序/APK,共用 Shell,加上内置设置和平台集成。 | -| 原生应用 | 实现 Makepad `AppModule` 的 Rust 模块,或通过窗口管理协议托管的独立程序。 | -| OctoScript 应用 | 通过准入的 `manifest.json` + `main.splash` bundle,由 App Hub 的 Card runner 解释执行。 | -| 宿主服务 | 按明确的调用应用身份执行某项操作并返回数据的 Rust 代码,不一定使用模型。 | -| 应用 Agent | octos 中按应用/账号限定的模型 Peer,拥有工作目录、会话及明确授予的工具。 | -| 系统 Agent | Shell 助手,拥有自己的工具策略和委派工具。 | -| ROM 特权 agent | 用于 Android 平台操作的 Java/Binder 服务,与模型驱动的系统 Agent 是不同组件。 | +| 桌面 | `desktop/src/main.rs` 启动 `octosense`,为 `octosense-shell` 提供薄入口。 | +| Home | `phone/src/main.rs` 启动 `octosense-home`,在共用 Shell 上增加设置和平台集成。 | +| 原生应用 | 实现 Makepad `AppModule` 的 Rust 模块,或通过窗口管理协议托管的可执行程序。 | +| 隔离脚本应用 | App Hub 的 Card runner 校验 `manifest.json`,在受限 Makepad Script/Splash VM 中运行 `main.splash`。 | +| 宿主服务 | Rust 按明确的应用身份执行操作并返回数据。 | +| 应用 Agent | 按应用/账号限定的 octos peer,拥有会话、工作目录及获授予的工具。 | +| 系统 Agent | Shell 的助手会话,拥有发现、委派和选定系统操作的工具。 | +| ROM 特权 agent | Android 的 Java/Binder 平台服务 `AgentPlatformService`。 | -Rust `trait` 定义接口,`impl AppModule` 实现接口;`Widget` 处理事件和绘图。这些本身不意味着线程、LLM 或 Tokio 任务。Splash 既可描述原生控件,也可作为隔离应用程序;其权限取决于宿主和策略。这里的 `main.splash` 使用 Makepad Script/Splash;独立的 Octoscript L0 解析/检查器及 `.card` 转换路径不是该程序的解析器。“OctoScript 应用”是这些指南采用的产品名称,不表示两套语言实现相同。 +隔离应用的 `main.splash` 使用 Makepad Script/Splash。L0 `.card` 文件经过 Octoscript +独立的解析/检查器,再通过 lowering 转为 Makepad 可渲染内容。产品中同时使用这两条路径; +阅读或修改某个文件时,沿着它实际的加载路径追踪。 -## 2. 从最小原生例子开始 +## 2. 运行 Reference,追踪原生托管 -准备依赖后,在仓库根目录运行(**本次未验证**): +准备依赖后,在仓库根目录运行: ```sh # 独立的 Reference 窗口。 cargo run --locked -p octosense-reference -# 链接到桌面中,并在启动后打开。 +# 把 Reference 链接进桌面,并在启动后打开。 MAKEPAD_WM_TEST_APP=reference cargo run --locked -p octosense --features app-reference -- --module reference -# 标准桌面产品。 +# 标准桌面:App Hub、Rinx、Terminal 和内核集成。 cargo run --locked --release -p octosense ``` -无需占用屏幕时,添加 `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=8000`,通过 `/help` 描述的 Makepad 控制接口检查界面,并用 `/quit` 退出。`--module` 选择托管方式,`MAKEPAD_WM_TEST_APP` 请求启动应用。 - -按以下顺序读源码: - -1. [`apps/reference/src/lib.rs`](../../apps/reference/src/lib.rs):`ReferenceView` 保存 `count: usize`;`handle_event` 接收按钮和输入动作、更新标签;`draw_walk` 把绘图交给内部 `View`。这是普通 UI 状态,没有 Agent。 -2. 同文件的 `ReferenceModule`:`register` 注册控件类型;`create` 返回包含根控件、服务执行器和退出回调的 `InstanceParts`。执行器明确返回“Reference has no tools”。原生应用不会自动拥有 Agent。 -3. [`native-apps.json`](../../native-apps.json):声明 Reference 的源码、feature、托管、存储和空 Agent 授权。工具根据它生成注册表和 Cargo feature 区块,不要直接改生成部分。 -4. [`desktop/src/main.rs`](../src/main.rs):导入 Shell `App` 并调用 `octosense_main!`。在 [`crates/shell/src/lib.rs`](../../crates/shell/src/lib.rs) 中,该宏委托给 Makepad `app_main!` 并设置包目录。 -5. 同文件的 `App::launch_app_with_args`:查找应用,检查脚本应用身份和准入,准备存储,必要时聚焦已有窗口,再选择模块或进程托管。 -6. [`crates/shell/src/module_host.rs`](../../crates/shell/src/module_host.rs) 的 `ModuleHost::create`:准备实例范围、存储命名空间、回复句柄、视口和 VM,再创建模块。只有声明且获得策略授权的 Agent 服务才会注入。 - -进程托管继续看 [`crates/shell/src/clients.rs`](../../crates/shell/src/clients.rs) 和 [`crates/process-apps`](../../crates/process-apps)。Shell 启动子进程,连接窗口管理协议,转发输入并显示其画面。子进程与 octos Peer 是两个独立概念。Terminal 在 macOS/Windows 以及满足 Vulkan + Wayland 条件的 Linux 上通常走进程路径;模块回退和覆盖见[桌面 README](../README.zh-CN.md)。 +隐藏窗口检查可添加 `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=8000`, +使用 `/help` 描述的 Makepad 控制接口,并通过 `/quit` 退出。 +`--module` 选择托管方式;`MAKEPAD_WM_TEST_APP` 请求启动应用。 + +按以下顺序阅读: + +1. [`apps/reference/src/lib.rs`](../../apps/reference/src/lib.rs): + `ReferenceView` 保存 `count`;`handle_event` 接收按钮和文本动作、修改标签; + `draw_walk` 将绘图交给内部 `View`。 +2. 同文件的 `ReferenceModule::register` 注册控件类型;`create` 返回 + `InstanceParts`,包含根控件、服务执行器和退出回调。`ReferenceExecutor` 不暴露工具。 +3. [`native-apps.json`](../../native-apps.json) 声明 Reference 的源码、feature、 + 托管、存储和空 Agent 授权。生成器据此生成原生应用注册表和 Cargo feature 区块。 +4. [`desktop/src/main.rs`](../src/main.rs) 导入 Shell 的 `App` 并调用 + `octosense_main!`。在 [`crates/shell/src/lib.rs`](../../crates/shell/src/lib.rs) + 中,该宏调用 Makepad 的 `app_main!` 并设置包目录。 +5. `App::launch_app_with_args` 查找注册的应用,按需检查脚本应用身份和准入, + 准备存储,必要时聚焦已有窗口,然后选择模块或进程托管。 +6. [`ModuleHost::create`](../../crates/shell/src/module_host.rs) 创建实例范围、 + 存储命名空间、回复句柄、视口和 VM,再创建模块。宿主策略决定它可以获得哪些已声明的 Agent 服务。 + +进程托管继续看 [`clients.rs`](../../crates/shell/src/clients.rs) 和 +[`crates/process-apps`](../../crates/process-apps)。Shell 启动子进程、连接窗口管理协议, +转发输入并显示子进程画面。Terminal 在 macOS/Windows,以及启用 Vulkan 的 Linux +Wayland 会话中通常走这条路径;模块回退和覆盖配置见[桌面 README](../README.zh-CN.md)。 + +原生应用还可以通过 [`peer_link`](../../crates/shell/src/peer_link/mod.rs) +访问自己的 Agent。进程应用在已有的、经过认证的 hub socket 上发送 `octos_peer` 消息。 +Shell 将帧归属到它启动的应用,检查 `agent.octos` 授权和用户同意,再把请求接到模块也使用的 +app-peer broker。模块的 `OctosPeer` 通道则通过 `module_connected` 和 +`on_module_frame` 接入同一路径。工具结果和取消沿该链路返回;进程死亡时,关闭它的上下文, +让等待中的调用失败,同时保留持久 peer。**当前发布的进程应用没有申请 Agent**: +Terminal 清单虽然暴露工具,但 `agent.octos` 列表为空。 ## 3. 运行并追踪脚本 bundle -标准桌面已包含选定的系统应用,可从启动器打开 News 或 Calendar。单独预览则使用 App Hub 仓库的 `card-host`;在准备好依赖的 App Hub 检出中运行(**本次未验证**): +桌面会打包选定的系统 bundle;可以从启动器打开 News 或 Calendar。 +单独预览时,先按 App Hub 仓库的说明准备依赖,然后在该检出目录运行 `card-host`: ```sh -# 将示例路径换成你的 OctoSense 检出目录。 +# 将路径替换为你的 OctoSense 检出目录。 cargo run --locked --release -p octosense-card-host --bin card-host -- --bundle /path/to/OctoSense/apps/news/bundle --system ``` -`--system` 接纳内置 `os.*` bundle,但不会给预览器添加 Shell 的宿主服务和 Agent UI。Mail 需要 Shell 的服务,可以在 OctoSense 根目录启用演示邮箱(**本次未验证**): +`--system` 接纳内置 `os.*` bundle。Shell 的宿主服务和 Agent UI 需要完整 Shell。 +例如,在 OctoSense 根目录运行 Mail 的演示服务: ```sh MAKEPAD_APP_CONFIG='{"mail_demo":true}' cargo run --locked --release -p octosense ``` -演示账号的密码是 `demo`,发送留在演示环境。新商店应用在 OctoScript-App-Design-Flow 中开发,经 App Hub 准入和发布。用本地目录测试完整安装路径,见[桌面 README](../README.zh-CN.md)。 - -[`desktop/system-apps.json`](../system-apps.json) 和 [`phone/system-apps.json`](../../phone/system-apps.json) 选择 `apps/` 中的 bundle。再看 [`crates/shell/src/apps.rs`](../../crates/shell/src/apps.rs) 中的启动器条目、`agent_apps` 和 `register_host_services`。App Hub 的 `CARD_MODULE` 是这些解释执行程序的原生宿主,与需显式开启的 AppCard 助手模块不同。 +演示账号密码为 `demo`,发送留在演示环境。新商店应用在 OctoScript-App-Design-Flow 中开发, +使用 App Hub 的准入/发布流程。[本地目录配方](../README.zh-CN.md#发布前试用自己的应用) +用于发布前验证安装到 Shell 的路径。 -manifest 请求能力,准入将其解析为策略。脚本的 `host.request(...)` 按应用身份检查;它既不是任意 Rust 调用,也不自动成为 LLM 工具调用。App Hub 的 `crates/appstore/src/services.rs` 定义 `HostService`、`ServiceCall` 和回复机制。调用携带应用身份和宿主目录,服务可以在执行前检查方法与调用者。 +[`desktop/system-apps.json`](../system-apps.json) 和 +[`phone/system-apps.json`](../../phone/system-apps.json) 选择 `apps/` 中的 bundle。 +阅读 [`apps.rs`](../../crates/shell/src/apps.rs) 中的启动器条目、`agent_apps` 和 +`register_host_services`。App Hub 的原生 `CARD_MODULE` 托管这些解释执行程序; +可选的 AppCard 助手使用自己的模块。 -## 4. 用工具追踪真实数据 +准入将 manifest 的能力请求解析为策略。脚本的 `host.request(...)` 按应用身份执行。 +App Hub 的 `crates/appstore/src/services.rs` 定义 `HostService`、`ServiceCall` 和回复机制; +调用携带应用身份和宿主目录,供服务检查。只有明确声明的 Agent 工具,才会把相应操作提供给模型。 -从 [`apps/calendar/bundle/tools.json`](../../apps/calendar/bundle/tools.json) 和 [`apps/calendar/host-service/src/lib.rs`](../../apps/calendar/host-service/src/lib.rs) 开始。JSON 声明工具和 schema,不包含实现。Rust `CalendarService` 实现宿主服务接口;`handle` 分派方法,`load`/`save` 管理 `/calendar/events.json`。 +## 4. 将工具追到应用数据和 Glance -“添加日程”的调用链: +从 [Calendar 的 tools.json](../../apps/calendar/bundle/tools.json) 和 +[`CalendarService`](../../apps/calendar/host-service/src/lib.rs) 开始。 +JSON 声明 schema 和策略;Rust 的 `handle` 分派方法,`load`/`save` 管理 +`/calendar/events.json`。 ```mermaid sequenceDiagram @@ -84,7 +118,7 @@ sequenceDiagram participant R as Shell 工具中继 participant C as Calendar Rust 服务 participant D as events.json - H->>A: 请求添加日程 + H->>A: 请求 Calendar 添加日程 A->>R: calendar.add_event 和结构化参数 R->>R: 检查调用者、授权、schema 和策略 R->>C: 以 os.calendar 身份执行 @@ -94,54 +128,134 @@ sequenceDiagram A-->>H: 回答原会话 ``` -[`crates/shell/src/host_tools/script_apps.rs`](../../crates/shell/src/host_tools/script_apps.rs) 加载工具并实现 `HostServiceExecutor`;`host_tools/relay.rs` 负责授权。`calendar.remove_event` 是破坏性操作,需要配置的宿主确认。`calendar.notify`/`agenda` 填入固定 `.card` 模板,调用 `register_host_services` 安装的发布回调,Shell 检查 `glance` 授权。模型提供参数,不编写可执行卡片代码。 +[`script_apps.rs`](../../crates/shell/src/host_tools/script_apps.rs) 加载工具并实现 +`HostServiceExecutor`;[`relay.rs`](../../crates/shell/src/host_tools/relay.rs) 负责授权。 +`calendar.remove_event` 需要破坏性操作审批。Shell 的 +[审批路由](../../crates/shell/src/approvals/mod.rs) 应用用户设定的常设规则,或显示确认面板; +已注册的 `confirm: app` 工具使用所属应用的面板。开发者模式提供另外一种由用户开启的覆盖。 +路由在仅所有者可访问的审计日志中记录决定。这些路径决定工具是否运行;模型只提供调用和参数。 -必须区分以下边界: +内置声明提供以下操作: -| 边界 | 实际权限 | +| 拥有 Agent 的应用 | 工具与实现 | | --- | --- | -| 脚本存储 | 应用的 storage 能力和隔离目录,仅使用运行时允许的 API。 | -| Agent 工作目录 | Peer 的应用/账号目录,仅能使用明确授予且受 Shell 策略限制的文件工具;不会挂载所有宿主服务数据库。 | -| 宿主服务数据库 | Rust 管理的 Calendar 日程、Mail 缓存与凭据、News 缓存等,经明确暴露的方法或工具访问;秘密保留在宿主界面和保险库中。 | - -当前例子并不相同:News 声明 `news.list` 和 `news.read`;Mail 的 **Agent 工具文件目前只有 `mail.notify`**,服务给 UI 提供的 `mail.list`、`mail.message`、`mail.send` 不会自动成为 Agent 工具。Calendar 窗口目前只是使用说明,不能通过脚本 `calendar` 能力列出或编辑日程,因为 App Hub 尚未提供该能力。 +| News | `news.list`、`news.read`、`news.notify`;News 宿主服务处理调用,并将通知交给 Shell。 | +| Mail | 只有 `mail.notify`;Mail 服务调用 Shell 的 `on_notify` 回调。`mail.list`、`mail.message`、`mail.send` 等 UI 操作没有对应的 Agent 声明。 | +| Calendar | `calendar.events`、`add_event`、`remove_event`、`notify`、`agenda`;Rust 服务管理日程及事件/议程卡片模板。 | +| Photos、Maps、YouTube、Camera | 只有 `.notify`;Shell 的 `NoticeService` 处理各应用的命名空间。Camera 由 Home 打包。 | + +AI providers 配置宿主,目前不声明应用 Agent。Calendar 的脚本窗口介绍如何询问其 Agent; +日程通过上述工具访问,App Hub 还没有提供脚本 `calendar` 能力。 + +共用通知的实现见 [`glance_notice.rs`](../../crates/shell/src/glance_notice.rs) 和 +[`resources/glance/notice.card`](../../crates/shell/resources/glance/notice.card)。 +Mail 和 News 保留自己的服务并安装通知回调;`serve_system_apps` 只为尚无服务的命名空间 +注册 `NoticeService`。`publish_args` 填入应用名称/图标、时间、标题和正文, +再由 `glance::publish_for` 检查应用的 `glance` 授权。通知卡片可以打开所属应用, +并设置 `notify: true`。Calendar 继续使用自己的事件和议程模板。 + +更通用的 [`glance.publish`](../../crates/shell/src/glance.rs) API 接受 L0 `source` +和可选 `data`,或自带值的 Splash `script`,两种卡片都在发布应用的策略下渲染。 +`notify: true` 排入一条 toast 通知;用户关闭卡片时,宿主的 `glance::dismiss` 删除它。 +上述固定通知工具接受文本参数,script-card API 则用于更丰富的应用界面。 +用户在这些界面上的操作使用应用自己的 API 权限。 + +实现旁的测试直接展示这些约定:`script_apps.rs` 中的 +`a_host_service_tool_runs_as_the_apps_own_request`、`glance_notice.rs` 中的 +`system_apps_without_a_service_of_their_own_get_the_notice_service`,以及 `glance.rs` 中的 +`a_script_card_is_admitted_as_it_is`。它们分别检查调用归属、命名空间回退和脚本卡片准入路径。 + +增加工具时,保持数据边界清晰: + +| 边界 | 访问路径 | +| --- | --- | +| 脚本存储 | 在应用能力和隔离目录限制下使用运行时 storage API。 | +| Agent 工作目录 | 通过获授权的文件工具和 Shell 策略访问 peer 的应用/账号目录。 | +| 宿主服务数据库 | 经明确的 Rust 方法/工具访问 Calendar 日程、Mail 缓存和 News 数据。凭据保留在宿主确认面板和保险库中。 | -跨应用访问也要显式声明:请求方在 `agent.tools` 中列出带点号的工具名,所有者提供可共享工具,中继授权并以正确身份执行。App Hub 准入还检查 `HostLimits.offered_tools`;默认不提供 `mail.send` 等任意带点名称,因此只改 `agent.tools` 不会让 bundle 自动通过准入。可写工作目录或聊天消息都不能授予另一应用的文件、凭据或 API。系统 Agent 委派及应用反向请求系统 Agent 的当前限制,见配套架构导读。 +跨应用调用由请求方在 `agent.tools` 中列出带点号的工具名,所有者必须声明可共享, +relay 也必须授权。准入还检查 `HostLimits.offered_tools`:默认提供的工具中没有 +`mail.send` 等名称。先补齐声明、准入 offer 和执行器路径,再将其写成可用的集成方案。 +[Agent 导读](../../docs/architecture-walkthrough.zh-CN.md)继续解释委派和向其他 Agent 请求帮助。 -## 5. 人如何直接与应用 Agent 对话 +## 5. 追踪人的对话 -Shell 为启用 Agent 的应用绘制 **Ask <app>** 面板。桌面上聚焦应用后使用栏按钮、Shift+F8 或菜单的“Ask this app's agent”。首次授权后才准备 Peer。F8 打开系统 Agent,它通过 `agents.ask` 请求同意并准备 peer,然后用 `peer_send_input` 委派、`peer_gather` 获取结果;卡片中的 `sys.chat` 也可以联系所属应用 Agent。手机目前还没有打开该面板的触摸入口。 +桌面上聚焦拥有 Agent 的应用,从栏按钮、Shift+F8 或菜单打开 **Ask <app>**。 +F8 打开系统 Agent。`agents.list` 报告应用 Agent;`agents.ask` 等待首次同意和 peer +准备完成,再返回 peer slug。系统 Agent 用 `peer_send_input` 发送任务,用 `peer_gather` +获取答案。卡片的 `sys.chat` 也可以访问其应用 Agent。手机触控导航尚无打开 Ask-app 面板的控件。 -阅读 `crates/shell/src/app_chat/`、`system_chat/`、`agents.rs`、`crates/ai-host/src/contained.rs` 和 `crates/app-peers/`。人的对话和系统 Agent 的对话使用应用 Peer 上不同的 lane/session;面板 Stop 只中断人的那次运行。“一个 Peer”不等于“一份共享记录”“一个 OS 线程”或“一个 Tokio 任务”。Makepad 事件循环处理 UI,broker/内核和通知通过各自通道工作;配套导读继续映射到具体任务。 +继续阅读 [`app_chat/`](../../crates/shell/src/app_chat/mod.rs)、 +[`system_chat/`](../../crates/shell/src/system_chat/mod.rs)、 +[`agents.rs`](../../crates/shell/src/agents.rs)、 +[`contained.rs`](../../crates/ai-host/src/contained.rs) 和 +[`app-peers`](../../crates/app-peers/README.md)。人的工作和系统 Agent 的工作使用 peer 上 +不同的 session/lane;面板的 Stop 中断人的回合。Makepad 处理 UI 事件,broker/内核通道 +传递请求和通知;配套导读将这些通道映射到 Rust 任务。 -还必须配置内核:`octos-core` 链接集成代码,不会自动生成桌面的 `octos` 可执行程序或提供商凭据。配置兼容的 `OCTOS_APP_CORE_BIN`,在 AI providers 中配置模型,参阅[内核指南](../../crates/kernel/README.zh-CN.md)。Android 打包 `liboctos.so`;桌面和 Android 通常运行子进程内核,OpenHarmony 使用进程内内核。内核托管方式与应用 UI 的模块/进程托管是两回事。 +桌面需配置兼容的 `OCTOS_APP_CORE_BIN`,并在 AI providers 中设置提供方; +`octos-core` 在构建中启用集成。详见[内核指南](../../crates/kernel/README.zh-CN.md)。 +Android 打包 `liboctos.so` 并作为子进程运行,OpenHarmony 在进程内运行内核。 +应用 UI 托管与内核托管分别选择。 -## 6. Home 在共用 Shell 外加上设置 +## 6. 追踪 Home 的设置和平台桥接 -在 **`phone/` 中运行 Cargo**,其 `.cargo/config.toml` 会选择手机版 bundle。桌面预览配方(**本次未验证**): +在 **`phone/` 中运行 Cargo**,让其 `.cargo/config.toml` 选择手机版 bundle: ```sh cargo run --locked --release -p octosense-home --features mobile-only -# 同时链接 Reference/Sheets;两个 feature 的职责不同。 +# 同时链接 Reference 和 Sheets。 cargo run --locked --release -p octosense-home --features mobile-only,mobile-apps ``` -[`phone/src/main.rs`](../../phone/src/main.rs) 的 `App` 包含 `#[deref] shell: ShellApp` 和 `SettingsRuntime`。解引用让代码可以访问 Shell 字段,并没有再启动一个 Shell 进程。`install_ext` 注册受信任的设置模块。`handle_event` 先处理设置的启动、计时和入口 intent,再让 Shell 处理事件,最后消费平台包和设置请求。调试丢失的更新时要注意这个顺序。 - -继续看 `phone/src/settings_app.rs`、`settings_script.rs` 和 `settings_script_host_facade.rs`:脚本控制器/UI 与 Rust 宿主校验配合。权限来自编译进来的受信任单例,不是脚本自称“settings”。`android_settings.rs` 根据 channel 分派观测结果和命令回复;已接受命令与随后观测到的平台状态不同,不能提前显示为已生效。 - -Android 路径继续进入 `phone/resources/android/java/dev/makepad/octosense/MakepadAppExtension.java`、其中调用的客户端和 `phone/android/contracts/`。System Bridge 的 `SystemBridgeService.java` 使用 Binder 回调和调用者检查。独立 Home 只有平台授予的权限/角色,安装 Home 不会获得 ROM 特权。[Home 构建说明](../../phone/README.zh-CN.md)介绍 APK 打包;桌面预览不能证明 Binder 或设备行为。 - -## 7. ROM 打包平台组件 - -阅读 [`rom/vendor/octosense/octosense.mk`](../../rom/vendor/octosense/octosense.mk) 和 `Android.bp` 中的产品配置,再看 [`rom/scripts/build-home.py`](../../rom/scripts/build-home.py)、`stage-home.py` 与 `stage-forks.sh`。构建产生 Home/Bridge APK 和回执,staging 校验并复制产物,LineageOS 构建产生镜像;安装、刷机、OTA 是另外的操作。 - -特权 Android 服务位于 `rom/vendor/octosense/agent/src/dev/makepad/octosense/agent/AgentPlatformService.java`。`caller` 检查 Binder UID、允许的包身份和平台签名;方法调用平台后端并返回能力/结果,AIDL 接口为 `IAgentPlatform.aidl`。它使用 Android 服务生命周期和 Binder 执行机制,不是 octos 模型循环,也不是 Rust Tokio 中的应用 Agent 任务。 - -Home 的 `AgentPlatformClient` 连接可选 ROM 服务。System Bridge、Quickstep、SystemUI、Settings broker 和特权 agent 是不同 Android 组件,不是任意应用都能调用的统一“系统 Agent”API。本次审查**未验证** ROM 启动和设备集成。 - -## 8. 单独理解较早的 AppCard 路径 - -`apps/appcard/module/src/lib.rs` 将可选 AppCard 助手适配为 `AppModule`;`apps/appcard/app/app` 实现 router/composer 和生成卡片,旁边是 transport/store/render crates。显式使用 `--features app-appcard` 开启;默认和 `mobile-apps` 不包含它。 - -AppCard 较早的路由/组合术语不等于所有当前系统/应用 Agent 的实现。系统聊天、应用聊天 broker 和隔离脚本 Agent 无需开启 AppCard;其旧 `personal-data` 邮箱读取器也不是当前 Mail 宿主服务的数据库 API。学习原生托管先看 Reference,学习已发布的应用工具先看 Calendar/News,修改这个可选产品时再看 AppCard。 +[`phone/src/main.rs`](../../phone/src/main.rs) 定义含有 `#[deref] shell: ShellApp` +和 `SettingsRuntime` 的 `App`。`install_ext` 注册受信任的设置模块。`handle_event` +先处理设置启动/计时及入口 intent,把事件传给 Shell,最后消费排队的平台包和设置请求。 +如果设置更新丢失,先检查这个顺序。 + +[`settings_app.rs`](../../phone/src/settings_app.rs)、 +[`settings_script.rs`](../../phone/src/settings_script.rs) 和 +[`settings_script_host_facade.rs`](../../phone/src/settings_script_host_facade.rs) +将脚本控制器/UI 接到 Rust 宿主校验。权限来自编译进来的受信任单例。 +[`android_settings.rs`](../../phone/src/android_settings.rs) 根据 channel 分派观测与结果。 +命令被接受的结果和随后观测到的平台状态使用不同处理器;后者确认设备当前实际状态。 + +Android 路径继续进入 +[`MakepadAppExtension.java`](../../phone/resources/android/java/dev/makepad/octosense/MakepadAppExtension.java)、 +其客户端,以及 [`phone/android/contracts/`](../../phone/android/contracts)。 +桥接的 [`SystemBridgeService.java`](../../phone/android/system-bridge/src/main/java/dev/makepad/octosense/bridge/SystemBridgeService.java) +使用 Binder 回调和调用者检查。独立 Home 在 Android 授予的权限/角色内工作, +ROM 提供额外的特权组件。[Home 构建说明](../../phone/README.zh-CN.md#构建与运行) +介绍 APK 打包及单独的设备验证步骤。 + +## 7. 追踪 ROM 打包和特权服务 + +阅读 [`octosense.mk`](../../rom/vendor/octosense/octosense.mk) 和 +[`Android.bp`](../../rom/vendor/octosense/Android.bp) 中的产品配置,再看 +[`build-home.py`](../../rom/scripts/build-home.py)、 +[`stage-home.py`](../../rom/scripts/stage-home.py) 和 +[`stage-forks.sh`](../../rom/scripts/stage-forks.sh)。构建产生 Home/Bridge APK 对和回执, +staging 校验并复制产物,LineageOS 构建产生镜像。安装、刷机和 OTA 分别有自己的脚本和验证步骤。 + +[`AgentPlatformService.java`](../../rom/vendor/octosense/agent/src/dev/makepad/octosense/agent/AgentPlatformService.java) +在 `caller` 中检查 Binder UID、允许的包身份和平台签名。 +[`IAgentPlatform.aidl`](../../rom/vendor/octosense/agent/src/dev/makepad/octosense/agent/IAgentPlatform.aidl) +定义的方法调用平台后端并返回能力/结果。Android 管理其服务生命周期和 Binder 执行; +LLM 系统对话则归前文介绍的 octos 内核所有。 + +Home 的 `AgentPlatformClient` 连接这一可选 ROM 服务。System Bridge、Quickstep、 +SystemUI 和 Settings broker 各自有 Android 角色及权限边界。 +按照 ROM 的[验证说明](../../rom/README.zh-CN.md#测试与验证), +在分配给本任务的设备上检查启动、平台操作和更新行为。 + +## 8. 追踪可选的 AppCard 产品 + +[`apps/appcard/module/src/lib.rs`](../../apps/appcard/module/src/lib.rs) 将 AppCard +适配为 `AppModule`;[`apps/appcard/app/app`](../../apps/appcard/app/app) 实现 +router/composer 和生成卡片,旁边还有 transport/store/render crates。 +使用 `--features app-appcard` 启用;默认构建和 `mobile-apps` 不包含它。 + +共用 Shell 独立实现系统聊天、应用聊天和隔离应用 peer。AppCard 的旧 `personal-data` +集成读取较早的原生 Mail 格式,而当前 Mail 在宿主服务中管理缓存。 +学习原生托管先看 Reference,学习应用工具先看 Calendar/News; +修改 AppCard 的路由和卡片生成产品时,再读它自己的文档。 diff --git a/docs/ai-services.md b/docs/ai-services.md index 4f258d1a..4ccf26d6 100644 --- a/docs/ai-services.md +++ b/docs/ai-services.md @@ -2,7 +2,7 @@ English | [简体中文](ai-services.zh-CN.md) -How the assistant is wired into OctoSense: the octos kernel, provider configuration, app peers and tools. Current implementation statements were checked against OctoSense `c19da8d` (octos `ae230ce0`, App Hub `58c3c8ae`) on 2026-10-01. Earlier dated runs below are historical evidence, not validation of this revision. “Implemented” means present in the inspected source; it does not claim a device or real-provider run. For the call-by-call tutorial and execution model, read the [architecture walkthrough](architecture-walkthrough.md). +How the assistant is wired into OctoSense: the octos kernel, provider configuration, app peers and tools. Use the [Cargo.toml](../Cargo.toml) dependency pins when following external code. For calls and the execution model, read the [architecture walkthrough](architecture-walkthrough.md). Dated runs below are historical validation records. This page is about the assistant *inside* OctoSense. Building an app needs no AI service and no particular coding agent: the app harness, [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow), works with any agent or none. Its [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) page is the app developer's short version of this one. @@ -30,11 +30,11 @@ For the whole system around it (processes per platform, agents, protocols, tools | A contained script app (system or store) asking the assistant | Implemented through exact declared `octos.*` services, with a kernel and first-use consent by default. Host tools and kernel-tool approvals route through the shell. `OCTOSENSE_CONTAINED_APPS=0` disables access; `1` is a developer consent bypass, not normal setup | [below](#contained-script-apps-system-and-store) | | One-shot model calls for contained apps (`model`, `model.complete`) | Works today ([#95](https://github.com/OctoSense-org/OctoSense/pull/95)): registered by `crates/ai-host` with the `llm` service, for apps granted `model` ([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24), in the shells' App Hub pin) | [below](#contained-script-apps-system-and-store) | | News data service (`news`, no model) | Merged ([#69](https://github.com/OctoSense-org/OctoSense/pull/69)); answers `os.*` apps only | [`apps/news/host-service`](../apps/news/host-service/README.md) | -| `glance.publish`: L0 cards on the glance screen | Merged ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)); contained apps granted the `glance` capability publish ([#86](https://github.com/OctoSense-org/OctoSense/pull/86)). `sys.digest` integration is a separate runtime path; [#87](https://github.com/OctoSense-org/OctoSense/pull/87) is historical tracking, not a current PR-status claim | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | +| `glance.publish`: L0/L1 source cards or Splash script cards | Merged ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)); contained apps granted the `glance` capability publish ([#86](https://github.com/OctoSense-org/OctoSense/pull/86)). `sys.digest` integration is a separate runtime path; [#87](https://github.com/OctoSense-org/OctoSense/pull/87) is historical tracking, not a current PR-status claim | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | | Approvals, first-use consent, developer mode | Works today ([#120](https://github.com/OctoSense-org/OctoSense/pull/120), [#118](https://github.com/OctoSense-org/OctoSense/pull/118)): the shell's approval router, standing rules and sheets, fed by the AI services bus and by the kernel's `host_tool` approvals through the host-tool relay ([#145](https://github.com/OctoSense-org/OctoSense/pull/145)); consent before an app's agent first runs; developer mode turned on only by the person | [architecture § Approvals](architecture.md#5-approvals) | | The system agent's tool set | Works today, enforced: octos's shell is never offered (the `_main` profile's `tool_policy`, [#117](https://github.com/OctoSense-org/OctoSense/pull/117)), and every kernel start sets the system session's exact kernel tool list (`session/tool_list/set`, octos#2648). Command execution is the Setup → Assistant → Command execution switch ([#132](https://github.com/OctoSense-org/OctoSense/pull/132)): `terminal.run`, each command approved live, in both module and process hosting where Terminal is available | [architecture § Tools and grants](architecture.md#4-tools-and-grants) | | Native apps declared once (`native-apps.json`), hosting per target; the Terminal a system app in its own process on the desktop | Works today ([#113](https://github.com/OctoSense-org/OctoSense/pull/113)) | [architecture § Native apps](architecture.md#native-apps-in-process-or-their-own-process) | -| An app's own agent: declarations versus execution | `tools.json`, generic-tool grants, peers and host-service executors are implemented for News/Mail/Calendar. `AGENT.md` prompt loading, bundle skills/model selection and automatic triggers remain gaps | [below](#planned-event-driven-app-agents-adr-0002) | +| An app's own agent: declarations versus execution | `tools.json`, generic-tool grants, peers and host-service executors are implemented for News/Mail/Calendar/Photos/Maps/Camera/YouTube. `AGENT.md` prompt loading, bundle skills/model selection and automatic triggers remain gaps | [below](#planned-event-driven-app-agents-adr-0002) | | Native apps in their own process reaching their agent (the peer link, ADR 0004 §5) | Built, no user yet. Makepad's client side ([OctoSense-org/makepad#54](https://github.com/OctoSense-org/makepad/pull/54), `makepad_ai_services::peer`) and the shell side ([#130](https://github.com/OctoSense-org/OctoSense/pull/130), `crates/shell/src/peer_link/`) are merged; no process app is granted an agent yet (the Terminal, the only process app, declares none) | [architecture § An app and its own agent](architecture.md#an-app-and-its-own-agent) | ## Architecture @@ -176,7 +176,7 @@ A script app runs in App Hub's Card runner and reaches the shell only through `h | `mail` | any app granted `mail` | Mail accounts the person signs in to on the host's sheet | | `calendar` | Calendar's agent as `os.calendar`; no public script capability | Rust event storage and fixed glance-card tools. The script window currently shows instructions; it cannot call this family through a general Calendar capability. | | `llm` | `os.*` apps only | Managing the assistant's providers (`llm.providers`, `llm.add_provider`, `llm.test`, `llm.import_qr`, …); **no prompt or completion method** | -| `news` | `os.*` apps only (`may_call` in the service) | News data, without a model. The News bundle now declares `news`; its agent exposes `news.list`/`news.read`. The background fetch timer does not yet trigger an LLM turn. | +| `news` | `os.*` apps only (`may_call` in the service) | News data, without a model. The News bundle now declares `news`; its agent exposes `news.list`/`news.read`/`news.notify`. The background fetch timer does not yet trigger an LLM turn. | | `glance` | apps granted the `glance` capability ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) | Publishing L0 cards to the glance screen, under the app's own id (`crates/shell/src/glance.rs`) | | `model` | apps granted the `model` capability ([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24)) | One-shot `model.complete {task, input, schema, class?, allow_urls?}` and `model.budget` ([#95](https://github.com/OctoSense-org/OctoSense/pull/95), `apps/ai-providers/host-service/src/complete/`, registered in `crates/ai-host/src/lib.rs`): `class` `fast` or `strong`; the host picks the model from the person's providers, validates the reply against the schema, refuses URLs unless asked, keeps a per-app daily budget; no tools, memory or history, and the app never sees a key | | `octos` | Exact declared services, a kernel and first-use consent by default | Uses broker identity `card.` (the actual peer slug is returned by `peer/prepare`). `octos.turn.start` takes non-blank `text` up to 32 KiB and optional `trigger`/`from`; the other calls take `{}`. `trigger: "person"` is `AppSaysPerson`, an app assertion, not a trusted human gesture or approval bypass. Both host-tool and other peer approvals route to the shell; replies over 2 MiB are refused. | @@ -197,7 +197,7 @@ A script's own assistant calls use declared `octos.*` services. Separately, the **Historical validation (not rerun for this revision).** The first row, the `llm` row and the `card-host` row were run in `card-host` (App Hub `362d832`) on 2026-09-27. The reply, the unsupported-arguments answer and the missing-kernel answer were run on macOS on 2026-09-28 in a release desktop with hidden windows, through a system app declaring `octos.session.open` and `octos.turn.start` opened from the launcher; with a kernel built at the then-pinned octos `7bec0918` and the person's provider, the reply came from the peer `card.`, whose memory namespace `app/card./…` appeared in the kernel's data. The text-length and switch-off answers are covered by `cargo test -p octosense-ai-host`, through the same dispatch. OctoScript-App-Design-Flow's [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) has the example app and the argument and answer shapes of the four `octos.*` calls as Rinx serves them. -The manifest's `agent` and admitted `tools.json` participate in shell agent discovery, tool loading and grants. News/Mail/Calendar have working host-service-backed declarations. The `profile`/model requirements, `AGENT.md` prompt content, bundle skills and automatic triggers are not fully consumed; `implemented_by: "app"` has no script executor. Mail currently declares only `mail.notify`, not its UI's read/send methods. The agent workspace does not automatically expose host-service databases. Rinx mini-app admission is a separate contract; do not assume App Hub metadata is supported there. +The manifest's `agent` and admitted `tools.json` participate in shell agent discovery, tool loading and grants. News/Mail/Calendar/Photos/Maps/Camera/YouTube have working host-service-backed declarations. The `profile`/model requirements, `AGENT.md` prompt content, bundle skills and automatic triggers are not fully consumed; `implemented_by: "app"` has no script executor. Mail currently declares only `mail.notify`, not its UI's read/send methods. The agent workspace does not automatically expose host-service databases. Rinx mini-app admission is a separate contract; do not assume App Hub metadata is supported there. ## Planned: event-driven app agents (ADR 0002) @@ -205,12 +205,12 @@ The manifest's `agent` and admitted `tools.json` participate in shell agent disc | Piece | ADR | Status | | --- | --- | --- | -| `tools.json`: names, input/output schemas, risk, confirmation, sharing and implementation | §4, §12 | Loaded by `host_tools/script_apps.rs`, registered on peers and routed to host-service executors. News, Mail and Calendar ship declarations. Arbitrary `implemented_by: "app"` script execution remains unavailable. | +| `tools.json`: names, input/output schemas, risk, confirmation, sharing and implementation | §4, §12 | Loaded by `host_tools/script_apps.rs`, registered on peers and routed to host-service executors. News, Mail, Calendar, Photos, Maps, Camera and YouTube ship declarations; AI providers has no app agent. Arbitrary `implemented_by: "app"` script execution remains unavailable. | | `AGENT.md`, data-only skills, model requirements, `background`, triggers | §2, §3 | Admitted metadata. Prompt/skill loading, model selection from these requirements and trigger scheduling remain unimplemented in the shell. Tool background eligibility alone does not schedule a turn. | | Kernel: host-registered tools per peer (`peer/tools/register`, `peer/tool/call`/`result`/`cancel`), tool-list and risk enforcement, approvals only on the host connection, an allowlist of generic tools, `peer/input` | §4, §13 | Kernel side merged: [octos#2567](https://github.com/octos-org/octos/pull/2567) (UPCR-2026-035), in the pin with its follow-ups (octos#2616). The shell side is on main: [#145](https://github.com/OctoSense-org/OctoSense/pull/145) (tool registration, the relay, `peer/input`) and G3 (per-app `generic_tools` from the manifests, `tools.json` loading, grants, executors for script apps' host services, schema and budget checks; `peer/input/reject`, octos#2621). | | Risk decides supervision: read and in-app act run unattended; destructive waits for the person (`confirm: host`: the kernel's approval path; `confirm: app`: the app's own sheet when the person is present, an approval request in the app's conversation when absent) | §4, §12 | Declared in App Hub (#18) and octos#2567. The shell's approval router, sheets and standing rules are merged ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)) and take the AI services bus's `confirm: host` calls; since [#145](https://github.com/OctoSense-org/OctoSense/pull/145) the kernel's `host_tool` approvals reach it through the relay ([architecture § Approvals](architecture.md#5-approvals)). Rinx's `send_message` already works the `confirm: app` way on its own surface. | | News M1: the `news` data service (no model) | First slice | Merged ([#69](https://github.com/OctoSense-org/OctoSense/pull/69)); issue [#60](https://github.com/OctoSense-org/OctoSense/issues/60). | -| News M2: `os.news` gets a peer and tools | First slice | Implemented: manifest `agent`, `news.list`/`news.read` tools, shell peer preparation and relay. | +| News M2: `os.news` gets a peer and tools | First slice | Implemented: manifest `agent`, `news.list`/`news.read`/`news.notify` tools, shell peer preparation and relay. | | News M3: triggers and an unattended run | First slice | Planned: [#62](https://github.com/OctoSense-org/OctoSense/issues/62). | | News M4: glance cards (`glance.publish`, the glance page and desktop panel) | §7, §8 | `glance.publish` ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)) and the `glance` capability for contained apps ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), with [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) merged; `sys.digest` integration has separate runtime/host requirements; [#87](https://github.com/OctoSense-org/OctoSense/pull/87) is historical tracking; issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63). | | M5: the system toolbox as granted tools | §6 | Implemented behind `toolbox-peers`: `crates/ai-host/src/toolbox_peers.rs` and the shell toolbox executor. Home enables the feature by default; desktop opts in. Tools still require admission/grants and consent; this is not a general conversation with the system agent. | @@ -222,14 +222,14 @@ The tracking issue is [#68](https://github.com/OctoSense-org/OctoSense/issues/68 ## Run and test locally -All commands below are **unverified in this documentation correction**; the walkthrough separately records the checks actually run. +The build/launch recipes below are **unverified**; read dependency versions from the root Cargo.toml. ### Desktop, with a throwaway kernel and profile -1. Build octos at the revision the root `Cargo.toml` pins (`ae230ce0`), in a checkout of [octos-org/octos](https://github.com/octos-org/octos) (the flags are `tools/kernel-artifact.py`'s; **unverified** at this revision in this page's refresh): +1. Build octos at the revision the root `Cargo.toml` pins, in a dedicated checkout of [octos-org/octos](https://github.com/octos-org/octos) (flags from `tools/kernel-artifact.py`; build/launch recipe **unverified**): ```sh - git checkout ae230ce04d57f3c29cf6c2518e5956a86c07d788 + git checkout --detach cargo build --release -p octos-cli --bin octos --no-default-features --features api,git,ast ``` diff --git a/docs/ai-services.zh-CN.md b/docs/ai-services.zh-CN.md index b6529864..6ca06404 100644 --- a/docs/ai-services.zh-CN.md +++ b/docs/ai-services.zh-CN.md @@ -2,7 +2,7 @@ [English](ai-services.md) | 简体中文 -本文介绍 OctoSense 的 octos 内核、提供方配置、应用 peer 和工具。当前实现说明已于 2026-10-01 对照 OctoSense `c19da8d`(octos `ae230ce0`、App Hub `58c3c8ae`)核查。下文较早的带日期运行记录是历史证据,不是此版本的验证。“已实现”表示所读源码中存在,不代表设备或真实提供方运行通过。逐步调用链与执行模型见[架构导读](architecture-walkthrough.zh-CN.md)。 +本文介绍 OctoSense 的 octos 内核、提供方配置、应用 peer 和工具。阅读外部源码时使用 [Cargo.toml](../Cargo.toml) 的依赖锁定版本。调用链与执行模型见[架构导读](architecture-walkthrough.zh-CN.md)。下方带日期的运行信息是历史验证记录。 本文讨论的是 OctoSense *内部*的助手。开发应用不需要任何 AI 服务,也不需要特定的编程 Agent:应用开发工具集 [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow) 适用于任何 Agent,也可以不用 Agent。它的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 页面是本文面向应用开发者的简短版本。 @@ -30,11 +30,11 @@ | 隔离脚本应用向助手提问 | 已实现:精确声明的 `octos.*` 服务、内核与默认的首次使用同意;宿主工具和内核工具审批都交给 Shell。`OCTOSENSE_CONTAINED_APPS=0` 禁用;`1` 是跳过同意的开发覆盖,不是正常设置步骤 | [见下文](#隔离运行的脚本应用系统应用和商店应用) | | 供隔离应用使用的一次性模型调用(`model`,`model.complete`) | 目前可用([#95](https://github.com/OctoSense-org/OctoSense/pull/95)):由 `crates/ai-host` 与 `llm` 服务一同注册,供获得 `model` 权限的应用使用([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24),已在 Shell 锁定的 App Hub 中) | [见下文](#隔离运行的脚本应用系统应用和商店应用) | | News 数据服务(`news`,不使用模型) | 已合入([#69](https://github.com/OctoSense-org/OctoSense/pull/69));只响应 `os.*` 应用 | [`apps/news/host-service`](../apps/news/host-service/README.md) | -| `glance.publish`:glance 屏幕上的 L0 卡片 | 已合入([#72](https://github.com/OctoSense-org/OctoSense/pull/72));获得 `glance` 权限的隔离应用可以发布([#86](https://github.com/OctoSense-org/OctoSense/pull/86))。`sys.digest` 有单独的运行时/宿主要求;[#87](https://github.com/OctoSense-org/OctoSense/pull/87) 是历史跟踪链接,不表示当前 PR 状态 | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | +| `glance.publish`:L0/L1 source 卡片或 Splash script 卡片 | 已合入([#72](https://github.com/OctoSense-org/OctoSense/pull/72));获得 `glance` 权限的隔离应用可以发布([#86](https://github.com/OctoSense-org/OctoSense/pull/86))。`sys.digest` 有单独的运行时/宿主要求;[#87](https://github.com/OctoSense-org/OctoSense/pull/87) 是历史跟踪链接,不表示当前 PR 状态 | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | | 审批、首次使用同意、开发者模式 | 已实现:Shell 审批路由、常设规则及面板接收 AI 服务总线和内核工具审批;首次运行先征求同意,开发者模式由用户开启 | [架构 § 审批](architecture.zh-CN.md#5-审批) | | 系统 Agent 的工具集 | 已强制:不提供 octos 内置 shell;精确设置系统会话内核工具列表。用户开启命令执行后通过 `terminal.run`,每次命令实时确认;Terminal 可用时模块和进程托管均支持 | [架构 § 工具与授权](architecture.zh-CN.md#4-工具与授权) | | 原生应用只声明一次(`native-apps.json`),按目标平台决定托管方式;Terminal 作为系统应用在桌面端以独立进程运行 | 目前可用([#113](https://github.com/OctoSense-org/OctoSense/pull/113)) | [架构 § 原生应用](architecture.zh-CN.md#原生应用进程内还是独立进程) | -| 应用自己的 Agent:声明与执行 | News/Mail/Calendar 的 `tools.json`、通用工具授权、peer 和宿主服务执行器已实现。`AGENT.md` 提示词加载、包内 skills/模型选择和自动触发器仍有缺口 | [见下文](#规划中事件驱动的应用-agentadr-0002) | +| 应用自己的 Agent:声明与执行 | News/Mail/Calendar/Photos/Maps/Camera/YouTube 的 `tools.json`、通用工具授权、peer 和宿主服务执行器已实现。`AGENT.md` 提示词加载、包内 skills/模型选择和自动触发器仍有缺口 | [见下文](#规划中事件驱动的应用-agentadr-0002) | | 独立进程中的原生应用访问自己的 Agent(peer link) | Makepad 客户端与 Shell `crates/shell/src/peer_link/` 均已实现。当前没有进程应用申请自己的 Agent;Terminal 声明了工具但未申请 peer | [架构 § 应用与它自己的 Agent](architecture.zh-CN.md#应用与它自己的-agent) | ## 架构 @@ -176,7 +176,7 @@ flowchart TB | `mail` | 获得 `mail` 授权的任何应用 | 用户在宿主面板上登录的邮件账号 | | `calendar` | Calendar Agent 以 `os.calendar` 身份调用;无公开脚本能力 | Rust 日程存储和固定 glance 卡片工具;脚本窗口目前只是说明,不能通过通用 Calendar 能力调用这个 family。 | | `llm` | 仅 `os.*` 应用 | 管理助手的提供方(`llm.providers`、`llm.add_provider`、`llm.test`、`llm.import_qr` 等);**没有提示词或补全方法** | -| `news` | 仅 `os.*` 应用(服务的 `may_call`) | 不使用模型的 News 数据服务。News bundle 已声明 `news`,其 Agent 暴露 `news.list`/`news.read`;后台抓取计时器尚不会启动 LLM 回合。 | +| `news` | 仅 `os.*` 应用(服务的 `may_call`) | 不使用模型的 News 数据服务。News bundle 已声明 `news`,其 Agent 暴露 `news.list`/`news.read`/`news.notify`;后台抓取计时器尚不会启动 LLM 回合。 | | `glance` | 获得 `glance` 权限的应用([#86](https://github.com/OctoSense-org/OctoSense/pull/86)、[App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) | 以应用自己的 id 向 glance 屏幕发布 L0 卡片(`crates/shell/src/glance.rs`) | | `model` | 获得 `model` 权限的应用([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24)) | 一次性的 `model.complete {task, input, schema, class?, allow_urls?}` 和 `model.budget`([#95](https://github.com/OctoSense-org/OctoSense/pull/95),`apps/ai-providers/host-service/src/complete/`,在 `crates/ai-host/src/lib.rs` 中注册):`class` 为 `fast` 或 `strong`;宿主从用户的提供方中挑选模型,按 schema 校验回复,除非请求否则拒绝含 URL 的回复,按应用管理每日预算;没有工具、记忆和历史,应用也看不到任何密钥 | | `octos` | 精确声明的服务、内核及默认的首次使用同意 | broker 身份为 `card.<应用 id>`,真实 peer slug 由 `peer/prepare` 返回。`octos.turn.start` 接受非空白、最多 32 KiB 的 `text` 和可选 `trigger`/`from`;其余调用接受 `{}`。`trigger: "person"` 是 `AppSaysPerson`,只是应用声明,不是受信任的人类操作或绕过审批的凭证。宿主工具和其他 peer 审批都交给 Shell;超过 2 MiB 的回复拒绝。 | @@ -195,9 +195,9 @@ flowchart TB | 获得 `llm` 授权的商店应用调用 `llm.*` | `llm is for OctoSense's own apps.` | | 在 App Hub 的 `card-host` 中调用任何服务 | `no service answers "" on this device`(`card-host` 不注册任何服务) | -**历史验证(本次未在当前版本重跑)。** 第一行、`llm` 一行和 `card-host` 一行已于 2026-09-27 在 `card-host`(App Hub `362d832`)中运行验证。回复、参数不合规的返回和缺少内核的返回已于 2026-09-28 在 macOS 上运行验证:release 版桌面端、隐藏窗口,经启动器打开一个声明了 `octos.session.open` 和 `octos.turn.start` 的系统应用;使用按当时锁定的 octos `7bec0918` 构建的内核和用户自己的提供方时,回复来自 peer `card.<应用 id>`,内核数据中出现了它的记忆命名空间 `app/card.<应用 id>/…`。文本长度和开关关闭的返回由 `cargo test -p octosense-ai-host` 覆盖,走的是同一个分发函数。OctoScript-App-Design-Flow 的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 给出了示例应用,以及 Rinx 提供的四个 `octos.*` 调用的参数和返回形状。 +**历史验证。** 第一行、`llm` 一行和 `card-host` 一行已于 2026-09-27 在 `card-host`(App Hub `362d832`)中运行验证。回复、参数不合规的返回和缺少内核的返回已于 2026-09-28 在 macOS 上运行验证:release 版桌面端、隐藏窗口,经启动器打开一个声明了 `octos.session.open` 和 `octos.turn.start` 的系统应用;使用按当时锁定的 octos `7bec0918` 构建的内核和用户自己的提供方时,回复来自 peer `card.<应用 id>`,内核数据中出现了它的记忆命名空间 `app/card.<应用 id>/…`。文本长度和开关关闭的返回由 `cargo test -p octosense-ai-host` 覆盖,走的是同一个分发函数。OctoScript-App-Design-Flow 的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 给出了示例应用,以及 Rinx 提供的四个 `octos.*` 调用的参数和返回形状。 -manifest 的 `agent` 和已准入 `tools.json` 已参与 Shell 的 Agent 发现、工具加载与授权;News/Mail/Calendar 已有宿主服务实现。`profile`/模型需求、`AGENT.md` 提示词、包内 skills 和自动触发器尚未完整消费,`implemented_by: "app"` 没有脚本执行器。Mail 当前只声明 `mail.notify`,不包含 UI 的读信/发信方法;Agent 工作目录不会自动暴露宿主数据库。Rinx 小程序准入是另一套约定,不能默认它支持 App Hub 的所有元数据。 +manifest 的 `agent` 和已准入 `tools.json` 已参与 Shell 的 Agent 发现、工具加载与授权;News/Mail/Calendar/Photos/Maps/Camera/YouTube 已有宿主服务实现。`profile`/模型需求、`AGENT.md` 提示词、包内 skills 和自动触发器尚未完整消费,`implemented_by: "app"` 没有脚本执行器。Mail 当前只声明 `mail.notify`,不包含 UI 的读信/发信方法;Agent 工作目录不会自动暴露宿主数据库。Rinx 小程序准入是另一套约定,不能默认它支持 App Hub 的所有元数据。 ## 规划中:事件驱动的应用 Agent(ADR 0002) @@ -205,12 +205,12 @@ manifest 的 `agent` 和已准入 `tools.json` 已参与 Shell 的 Agent 发现 | 组成部分 | ADR | 状态 | | --- | --- | --- | -| `tools.json`:名称、输入输出 schema、风险、确认、共享和实现 | §4、§12 | `host_tools/script_apps.rs` 已加载、注册到 peer 并转发到宿主服务执行器;News/Mail/Calendar 已声明工具。任意 `implemented_by: "app"` 脚本工具执行仍不可用。 | +| `tools.json`:名称、输入输出 schema、风险、确认、共享和实现 | §4、§12 | `host_tools/script_apps.rs` 已加载、注册到 peer 并转发到宿主服务执行器;News/Mail/Calendar/Photos/Maps/Camera/YouTube 已声明工具。任意 `implemented_by: "app"` 脚本工具执行仍不可用。 | | `AGENT.md`、只含数据的 skills、模型需求、`background` 和触发器 | §2、§3 | 已准入的元数据;Shell 尚未实现提示词/skill 加载、按这些需求选模型和触发调度。工具可后台运行不等于会自动启动回合。 | | 内核:宿主注册工具、风险/列表检查、宿主审批、通用工具白名单和 `peer/input` | §4、§13 | 已实现并在锁定版本中;Shell 注册工具、接收输入、检查 schema/预算并通过 relay 调用执行器。见 `crates/app-peers` 和 `crates/shell/src/host_tools/`。 | | 风险决定监督方式:read/应用内 act 与 destructive,`confirm: host/app` | §4、§12 | 已实现:AI 服务总线和内核 `host_tool` 审批进入 Shell 路由,其他 peer 内核工具审批也由宿主处理。`confirm: app` 需要注册所属应用面板;Rinx 的总线发送面板不代表已注册到 peer。 | | News M1:`news` 数据服务(不使用模型) | 第一个切片 | 已合入([#69](https://github.com/OctoSense-org/OctoSense/pull/69));issue [#60](https://github.com/OctoSense-org/OctoSense/issues/60)。 | -| News M2:`os.news` peer 及工具 | 第一个切片 | 已实现:manifest `agent`、`news.list`/`news.read`、Shell peer 准备与 relay。 | +| News M2:`os.news` peer 及工具 | 第一个切片 | 已实现:manifest `agent`、`news.list`/`news.read`/`news.notify`、Shell peer 准备与 relay。 | | News M3:触发器和无人值守运行 | 第一个切片 | 规划中:[#62](https://github.com/OctoSense-org/OctoSense/issues/62)。 | | News M4:glance 卡片(`glance.publish`、glance 页面和桌面面板) | §7、§8 | `glance.publish`([#72](https://github.com/OctoSense-org/OctoSense/pull/72))和供隔离应用使用的 `glance` 权限([#86](https://github.com/OctoSense-org/OctoSense/pull/86),配合 [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22))已合入;`sys.digest` 有单独的运行时/宿主要求;[#87](https://github.com/OctoSense-org/OctoSense/pull/87) 是历史跟踪链接,不表示当前 PR 状态;issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63)。 | | M5:作为获授权工具的系统工具箱 | §6 | 已在 `toolbox-peers` feature 下实现,见 `crates/ai-host/src/toolbox_peers.rs` 和 Shell 工具箱执行器。Home 默认开启,桌面需显式开启;仍需准入、授权和同意,不是与系统 Agent 的通用对话。 | @@ -222,14 +222,14 @@ manifest 的 `agent` 和已准入 `tools.json` 已参与 Shell 的 Agent 发现 ## 本地运行与测试 -以下命令**本次文档修正未验证**;架构导读另行记录实际运行的检查。 +以下构建/启动配方 **unverified(未验证)**;依赖版本取自根 Cargo.toml。 ### 桌面端:使用临时的内核与配置 -1. 在 [octos-org/octos](https://github.com/octos-org/octos) 的检出中,构建根 `Cargo.toml` 锁定的版本(`ae230ce0`;参数与 `tools/kernel-artifact.py` 相同;本次更新未在此版本上运行,**unverified**): +1. 在 [octos-org/octos](https://github.com/octos-org/octos) 的检出中,构建根 `Cargo.toml` 锁定的版本(参数来自 `tools/kernel-artifact.py`;构建/启动配方 **unverified,未验证**): ```sh - git checkout ae230ce04d57f3c29cf6c2518e5956a86c07d788 + git checkout --detach cargo build --release -p octos-cli --bin octos --no-default-features --features api,git,ast ``` diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md index d25c254f..8145e089 100644 --- a/docs/architecture-walkthrough.md +++ b/docs/architecture-walkthrough.md @@ -2,7 +2,7 @@ English | [简体中文](architecture-walkthrough.zh-CN.md) -This is a reading path for a Rust developer who knows structs, traits and functions but is new to OctoSense and agents. It follows OctoSense `c19da8d` and its Cargo-pinned octos `ae230ce0`, inspected on 2026-10-01. The [architecture reference](architecture.md) explains the broader design; this tutorial follows calls and ownership in the implementation. An ADR describes a decision, not proof that all its steps execute today. +This walkthrough follows a message from an app window through the shell, agent kernel and tool executor. Start here if you know Rust but are new to OctoSense or agents. The [architecture reference](architecture.md) describes the design; this guide follows implementation calls and ownership. Read dependency versions from [Cargo.toml](../Cargo.toml) and [native-runtime.lock.json](../native-runtime.lock.json). ADRs record decisions; remaining implementation work is listed in §11. ## 1. Give each name one meaning @@ -19,7 +19,7 @@ This is a reading path for a Rust developer who knows structs, traits and functi | Tool / host service | A tool is an operation offered to the model. A host service is Rust code called by an app or tool executor. Exposing one API does not automatically expose the other. | | `AGENTS.md` / `AGENT.md` | Repository contributor instructions / an app-bundle agent-instructions artifact. The bundle artifact is admitted by App Hub, but is not yet loaded into the shell peer's prompt. | -For the other repositories, continue with [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow), [App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub), [Octoscript-Makepad](https://github.com/OctoSense-org/Octoscript-Makepad) and [octos](https://github.com/octos-org/octos). Their detailed tours are [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/CODE-WALKTHROUGH.md), [App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/docs/CODE-WALKTHROUGH.md), [framework](https://github.com/OctoSense-org/Octoscript-Makepad/blob/main/docs/architecture-walkthrough.md) and [octos integration](https://github.com/octos-org/octos/blob/main/docs/octosense-integration-walkthrough.md) (companion documentation changes must be published before these new links resolve on GitHub). Read each repository's own lock: a nearby checkout's `main` may differ from the revision this shell uses. +The companion code tours cover [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/docs/junior-architecture-walkthrough/docs/CODE-WALKTHROUGH.md), [App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/docs/junior-architecture-walkthrough/docs/CODE-WALKTHROUGH.md), [Octoscript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad/blob/docs/junior-architecture-walkthrough/docs/architecture-walkthrough.md) and [octos](https://github.com/octos-org/octos/blob/docs/junior-architecture-walkthrough/docs/octosense-integration-walkthrough.md). These links select the published documentation branches; runtime versions remain controlled by each consumer's dependency pins. ## 2. Start at the executable, then follow the app host @@ -30,11 +30,11 @@ The launch choices come from [native-apps.json](../native-apps.json), [AppRegist | What you launch | Follow the code | What is actually running | | --- | --- | --- | | Native Rust module, such as Reference or Rinx | [module_host.rs](../crates/shell/src/module_host.rs): module creation, scoped handles, assistant/storage offers | Rust code and UI in the shell process; each instance gets a script isolate. The isolate does not isolate arbitrary Rust memory. | -| Native process app, currently desktop Terminal where supported | [clients.rs](../crates/shell/src/clients.rs), [hub.rs](../crates/shell/src/hub.rs), [process-apps](../crates/process-apps/src/lib.rs) | A child executable renders frames and exchanges input/AI-bus messages over the authenticated Makepad hub. This is separate from the octos protocol connection. | +| Native process app, currently desktop Terminal where supported | [clients.rs](../crates/shell/src/clients.rs), [hub.rs](../crates/shell/src/hub.rs), [process-apps](../crates/process-apps/src/lib.rs) | A child executable exchanges frames, input and AI-bus messages over the authenticated Makepad hub socket. An `octos_peer` envelope on that socket also supports its assistant link; see §5. Shipped process apps currently request no `agent.octos` services. | | Contained script app | App Hub's `CARD_MODULE`, reached through `apps.rs` | The Card runner admits the bundle and makes a restricted, nested Splash VM; capabilities limit access to host services and platform APIs. No Rust executable is compiled per bundle. | -| L0 glance card | [glance.rs](../crates/shell/src/glance.rs), [glance_chat.rs](../crates/shell/src/glance_chat.rs) | Checked card content lowered/rendered by the runtime, with host-provided data and chat. The card is not another peer. | +| Glance card | [glance.rs](../crates/shell/src/glance.rs), [glance_chat.rs](../crates/shell/src/glance_chat.rs) | An L0/L1 `source` card is checked and lowered with host data; a Splash `script` card runs interactive handlers under its publisher's policy. `notify` adds a toast/shade entry. UI dismissal calls `glance::dismiss`; apps use `glance.withdraw`. Chat reaches the publisher's peer. | -Read the product tutorials for command details: [desktop](../desktop/README.md), [Home](../phone/README.md), [ROM](../rom/README.md), and [system apps](../apps/README.md). A minimal developer route is below. **The launch/build commands in this block are source-checked but unverified in this review; no visible app or device was launched.** Run from this repository root: +Read the product tutorials for command details: [desktop](../desktop/README.md), [Home](../phone/README.md), [ROM](../rom/README.md), and [system apps](../apps/README.md). A minimal developer route is below. **Launch/build recipes below are unverified; platform prerequisites are in the product READMEs.** Run from this repository root: ```sh python3 tools/setup.py --hub /path/to/existing-clones @@ -49,7 +49,7 @@ OCTOS_APP_CORE_BIN=/path/to/pinned/octos \ The AI providers host-owned sheet must also configure a provider/model before a real conversation can run. A Rust build does not provision those credentials. `OCTOS_APP_CORE_BIN` names a file; this kernel launcher does not search `PATH`. For automated UI work use the existing hidden-window instructions in the product README. -For a script app, Design Flow's `tools/octo` wraps App Hub's `card-host` and `hub` commands. It is a Python development CLI, unrelated to the octos kernel. `card-host` exercises the contained UI and policy; it does not install the shell's Mail, Calendar, provider or peer services. Use a shell to test those integrations. Do not interpret successful `hub check` as a successful agent turn. +For a script app, Design Flow's Python `tools/octo` CLI wraps App Hub's `card-host` and `hub` commands. Run a bundle with `tools/octo run /path/to/bundle` from the Design Flow checkout (unverified launch recipe). The standalone runner exercises contained UI and policy. Use a shell to test Mail, Calendar, provider and peer services; those are registered by the shell. A `hub check` pass validates the bundle's admission contract. ## 3. Find who owns the kernel @@ -60,7 +60,7 @@ Read [ai-host/src/lib.rs](../crates/ai-host/src/lib.rs), then [kernel/src/lib.rs 3. `launch::resolve` selects a desktop child (`OCTOS_APP_CORE_BIN` or an explicit program), Android's executable packaged as `liboctos.so`, or an embedded OpenHarmony service. iOS has no kernel here. 4. `kernel::supervise` owns the running process/task and frame pump. `Router` correlates consumer request IDs and session events over the one physical protocol connection. 5. The protocol is OUP, JSON-RPC messages and asynchronous notifications. Ordinary mode uses newline-delimited JSON over stdio. Enabling Talk to Octos selects a host-managed loopback WebSocket; it does not start an extra kernel for each client. -6. Provider changes restart the generation. Consumers must reconnect and rebind. Dropping a Rust `Connection` is not deleting the peer's saved memory. +6. Provider changes restart the generation. Consumers must reconnect and rebind. A peer's memory outlives any `Connection`. The privileged Android service in the ROM is a different use of the word “agent”: it performs permitted platform operations through the Android bridge. It does not run the system LLM conversation. @@ -68,11 +68,11 @@ The privileged Android service in the ROM is a different use of the word “agen Open [system_chat/mod.rs](../crates/shell/src/system_chat/mod.rs), [session.rs](../crates/shell/src/system_chat/session.rs), [link.rs](../crates/shell/src/system_chat/link.rs), and [system_tools.rs](../crates/kernel/src/system_tools.rs). -The assistant pane sends a `Command` to its worker. The `Driver` opens `_main:api:octosense#system`, reads history and starts a turn. Incoming events update a chat model, and `SignalToUI` wakes the Makepad event loop to draw a snapshot. The UI is not awaiting the model on its drawing thread. +The assistant pane sends a `Command` to its worker. The `Driver` opens `_main:api:octosense#system`, reads history and starts a turn. Incoming events update a chat model, and `SignalToUI` wakes the Makepad event loop to draw a snapshot. The system agent is a session on the `_main` profile. The host narrows its kernel tools using `session/tool_list/set`; `SYSTEM_AGENT_TOOLS` includes `peer_list`, `peer_send_input`, `peer_gather` and `peer_respond`. Its normal command-execution route, if the person enables it, is the shell's `terminal.run` tool and approval UI. It is not octos's builtin `shell` tool. -[agents.rs](../crates/shell/src/agents.rs) adds two useful host tools: `agents.list` discovers app agents and their availability; `agents.ask` requests first-use consent. `agents.ask` is not a universal app-to-system chat API, and the model cannot grant consent itself. +[agents.rs](../crates/shell/src/agents.rs) adds two useful host tools: `agents.list` discovers app agents and their availability; `agents.ask` opens first-use consent and waits for a ready peer slug. On success the system agent uses `peer_send_input` to submit the task; the ask call itself only prepares access. The person controls first-use consent. ## 5. Prepare one app peer, then give it two lanes @@ -85,6 +85,8 @@ Read [app-peers/src/contract.rs](../crates/app-peers/src/contract.rs) before the A native module receives its handle through [hosted.rs](../crates/app-peers/src/hosted.rs) and [injection.rs](../crates/app-peers/src/injection.rs). A contained app reaches the same broker through [contained.rs](../crates/ai-host/src/contained.rs). A script agent is eligible when its manifest declares assistant services, an `agent` block, or the bundle carries `tools.json`. Eligibility still requires a kernel, consent and an active account where applicable. +Native process clients use [peer_link](../crates/shell/src/peer_link/mod.rs): `OctosPeer` messages share the authenticated hub socket in an `octos_peer` envelope. The shell derives the app/instance from the launched client, checks the exact `native-apps.json` `agent.octos` grants and consent, then forwards session/history/turn/interrupt operations to that app's broker. An in-process module can use the same client through a parked link claimed by `module_host`. The injected `OctosAppService` is another adapter to this broker. Process death cancels outstanding work and closes request contexts while keeping the durable peer; uncertain writes return `outcome_unknown`. + `card.os.news` is the broker's app identity, not necessarily the kernel's generated peer slug. `peer/prepare` returns that slug, the peer session and a host credential; use the returned values. Peers are keyed by app and account. Accountless apps use `device`; Mail uses the host-reported signed-in account. `ensure_peer` resumes the recorded peer, verifies its namespace, and registers tools before a turn can run. ```mermaid @@ -120,7 +122,7 @@ The broker's `driver_of` and `take_over` handle multiple native instances sharin | System assistant pane, F8 | `system_chat`: system session; routes app questions raised during system-delegated work here too. | | “Ask ”, Shift+F8 | [app_chat/mod.rs](../crates/shell/src/app_chat/mod.rs): `agents::conversation`, subscription to both lanes and merged history. Send starts the person's context turn. | | An app's own native chat | Injected `OctosAppService::open_conversation`; the app renders its events. | -| A script app's own chat | Exact granted `octos.session.open`, `octos.session.history`, `octos.turn.start`, `octos.turn.interrupt` calls through `host.request`. Today's News/Mail/Calendar agents can be shell-driven without their script declaring these calls. | +| A script app's own chat | Exact granted `octos.session.open`, `octos.session.history`, `octos.turn.start`, `octos.turn.interrupt` calls through `host.request`. The shipped system-app agents are shell-driven without their scripts declaring these calls. | | A published card's chat | `sys.chat` → [l0-chat](../crates/l0-chat/src/lib.rs) and [glance_chat.rs](../crates/shell/src/glance_chat.rs). Publisher checks bind it to the card's owning app. | Phone touch navigation does not yet expose an equivalent control to open the Ask-app panel; app-owned chat and published-card chat are separate surfaces. The Ask-app panel's Stop interrupts the human lane; “Stop the system agent's task” targets the other lane. The lower-level conversation `ContextOp::Interrupt` is broader and can interrupt both: do not assume all Stop surfaces call the same method. Hiding the Ask panel keeps its context/subscription; changing app or revoking access closes it. @@ -139,12 +141,37 @@ For a concrete example, follow Calendar's `calendar.events`: 2. `script_apps::from_bundle` loads admitted declarations; `install` adds them to the relay catalog and installs a `HostServiceExecutor`. 3. The peer's driving broker registers the exact tool roster with `peer/tools/register`. A model can now request that declared tool. 4. octos emits `peer/tool/call`. The broker stamps the actual caller/account/context and passes it to the shell's `ToolHost`. -5. `Relay::handle` checks authorization, consent, account state, input schema, size and call budgets. Required approvals are resolved through the shell. +5. `Relay::handle` checks authorization, consent, account state, input schema, size and call budgets. Approval-gated calls enter the router described below. 6. The executor invokes the Calendar host service as the **owning app**, which reads [Calendar's store](../apps/calendar/host-service/src/lib.rs). The reply queue returns the outcome; output schema/size are checked and `ToolReply` sends at most one `peer/tool/result`. 7. The model consumes that JSON result and continues its turn. It may answer in text or call another granted tool. The declaration is not the implementation. `implemented_by: "host-service"` works only where the service exists and the owner may call it. `implemented_by: "app"` is admitted metadata, but the Card runner's script executor is not implemented; it returns unavailable. Neither a copied `tools.json` nor a successful gate check creates missing service code. +The executor depends on the tool's owner. [host_tools/mod.rs](../crates/shell/src/host_tools/mod.rs) collects calls from broker threads into an inbox; the UI event loop pumps that inbox and queues replies. + +| Tool route | Executor boundary | +| --- | --- | +| Contained app, `implemented_by: "host-service"` | `HostServiceExecutor` invokes the admitted owner's Rust service. | +| Native module | Its `OctosAppService::set_tool_executor` callback handles the call. | +| Native process | `peer_link` sends a tool request to the client over its authenticated hub socket; registration and grants are still required. | +| System `terminal.run` | The shell types an approved command into the visible Terminal through its AI bus; enabled by the Command execution setting. | +| `files.list/read/search` | Shell executor over the caller's permitted account workspace, on Unix. | +| `dev.run` | Shell executor available to peers covered by developer mode. | +| Toolbox tools | Registered toolbox executor/workflow, behind the `toolbox-peers` feature and the app's grants. | + +### Approval order + +First-use agent consent, tool grants and per-call approval are separate checks. For an approval request, [approvals/router.rs](../crates/shell/src/approvals/router.rs) applies this order: + +1. An external client's turn stays with that client: the shell neither answers nor expires its prompts. +2. Developer mode approves requests for the apps it covers, including `auto_approvable: false` and `confirm: app`. +3. A `confirm: app` tool goes to its owning app's registered confirmation sheet, with the caller shown. Standing rules do not answer it. If no sheet registers before `app_wait_s`, the request is refused. +4. Requests marked `auto_approvable: false`, unknown outcomes, and calls classified as external connections require the person. +5. The person's standing rules may decide eligible requests. Incoming-content runs are skipped unless a rule explicitly includes them. +6. Otherwise, a shell confirmation sheet asks the person; calls from one system task may be batched. + +Each decision is delivered once and recorded in an owner-only audit log; automatic decisions also produce a notice. A held host-connection request expires as denied after `OCTOSENSE_PROMPT_DEADLINE_SECS` (default ten minutes). The host-tool audit stores an argument digest rather than raw arguments. A model's text answer or `peer_respond` cannot approve a tool call. + ## 8. What “access the app's data” actually means There are several stores, with separate ownership: @@ -158,7 +185,7 @@ There are several stores, with separate ownership: | Agent transcript and memory | octos session/context and `app//acct-` namespaces. These are separate from the app's business data. | | Secrets | Host-owned secret store/sheets; not the agent workspace or script state. | -For example, Calendar keeps `calendar/events.json` under its host directory and exposes operations through `calendar.*`. News exposes `news.list` and `news.read`. Mail's current agent declaration exposes **only `mail.notify`**; the Mail UI's ability to list messages or send mail does not mean the model has those tools. The older AppCard personal-data importer is not automatically synchronized with current Mail's store. +For example, Calendar keeps `calendar/events.json` under its host directory and exposes operations through `calendar.*`. News exposes `news.list`, `news.read` and `news.notify`. Photos, Maps, Camera and YouTube expose only their own `.notify`; these tools publish a shared notice card through [glance_notice.rs](../crates/shell/src/glance_notice.rs). AI providers has no app agent. Mail's current agent declaration exposes **only `mail.notify`**; the Mail UI's ability to list messages or send mail does not mean the model has those tools. The older AppCard personal-data importer is not automatically synchronized with current Mail's store. Account directory names use a SHA-256-derived tag; peer memory names use the broker's FNV-derived tag. These are compatibility identifiers, not interchangeable paths. Sign-out suspends access and retains data; account removal/uninstall additionally requests `peer/purge`, retrying busy peers. A peer's saved workspace cannot silently change on resume. @@ -170,13 +197,11 @@ Three operations are easy to confuse: **Calling another app's API as a tool:** `Catalog::owner_of` resolves an owner; `may_call` requires an existing declaration plus `shareable: true` and a grant for that caller (outside explicit developer-mode rules). Script manifests request dotted names through `agent.tools`; native entries use their reviewed grants. Admission is a separate prerequisite: App Hub `HostLimits.offered_tools` must offer a requested name; its default does not offer arbitrary names such as `mail.send`. A relay implementation does not override that gate. The relay calls the owner's executor without having to ask the owner's model. The receiving app's data remains behind that executor. Current owner resolution covers native namespaces, toolbox namespaces and `os.`; it is not an arbitrary installed-store-app discovery mechanism. -**A question or system facility:** an app agent can call a granted `ask_user_question`. [questions/mod.rs](../crates/shell/src/questions/mod.rs) routes it according to the initiating turn: system chat for a system-delegated turn, app conversation for a human/app turn. A person answers on a shell surface. This is not a way for a script to obtain system-agent privileges. octos has peer-supervision mechanisms, but the shell does not give every contained app a general `ask_system_agent` API or unrestricted peer tools. Likewise the [system toolbox](../crates/toolbox/README.md) supplies granted Rust tools/workflows; calling it is not talking to the system-agent conversation. - -The system agent's `peer_respond` capability is not permission to approve an app's action for the person. Tool approvals and human questions have distinct protocol messages and host-owned answer handles. Prompt deadlines deny/decline unanswered prompts; they never turn silence into consent. +**A question or system facility:** an app agent can call a granted `ask_user_question`. [questions/mod.rs](../crates/shell/src/questions/mod.rs) routes it by the initiating turn: system chat for system-delegated work, app conversation for a human/app turn. The person answers on a shell surface. Apps receive system facilities as explicitly granted tools, such as [toolbox](../crates/toolbox/README.md) workflows. A general app-to-system-agent conversation RPC remains unimplemented. `peer_respond` handles peer coordination; approval messages have separate host-owned answer handles. ## 10. Map the architecture to Rust execution -An `async fn` returns a future; polling it advances work until it must wait. A Tokio task is a scheduled future. An OS thread runs many task polls. A persisted session or peer can outlive every task currently handling it. +A peer is persisted identity and state. A turn uses runtime tasks while it executes; the peer survives those tasks. Read the ownership and scheduling boundaries separately: | Layer | Actual execution model | Source | | --- | --- | --- | @@ -185,7 +210,7 @@ An `async fn` returns a future; polling it advances work until it must wait. A T | Shell kernel service | Lazily built Tokio runtime: **2 worker threads**, **8 MiB stacks**. One generation supervisor task owns transport and process lifecycle, with auxiliary I/O tasks | `kernel/src/lib.rs::Inner::runtime`, `kernel.rs::supervise` | | App broker | **Each `Broker::new` builds a runtime with 1 worker thread**. Link pump, request futures, retries and deadline tasks run there. Multiple brokers may share one durable peer | `app-peers/src/broker.rs` | | Embedded OpenHarmony kernel | `serve_io` is spawned on the host runtime over `tokio::io::duplex`; no child executable | `kernel.rs::start` | -| octos OUP turn | Active-turn admission precedes a spawned `run_standalone_turn`; its agent/model processing and progress/heartbeat use further tasks | pinned octos `crates/octos-cli/src/api/ui_protocol_transport.rs` | +| octos OUP turn | A spawned orchestration task waits on a `oneshot` start barrier until active-turn admission succeeds; `run_standalone_turn` then spawns agent processing and auxiliary tasks | pinned octos `crates/octos-cli/src/api/ui_protocol_transport.rs` | | octos transport output | WebSocket has an async writer task; embedded/stdio uses a bounded synchronous queue and an ordinary writer thread. Transport variants are not identical | same octos file | | Host service / file executor | Depends on the service: UI pump, callback/reply queues, worker threads for blocking operations. Not universally a Tokio task per service or app | `host_tools/files.rs`, App Hub `services.rs`, app host services | @@ -207,17 +232,19 @@ flowchart LR Read `mpsc` as a many-sender mailbox, `oneshot` as one correlated answer, and `watch` as the latest lifecycle/readiness state. In the broker, request IDs map replies to `oneshot` senders; its link loop uses `tokio::select!` for outbound and inbound traffic. The kernel supervisor selects control messages, kernel output and process exit. `Arc` shares ownership, `Weak` avoids keeping a dropped broker/context alive, and generation/epoch checks reject replies from an obsolete account or connection. -The broker's synchronous `bind`/`host_request` wrappers wait for channel replies: do not call such blocking interfaces from a rendering callback. Async model I/O can overlap across sessions; synchronous filesystem work still needs the existing worker boundary. “One peer per app/account” is an identity and isolation rule, **not one Tokio task or thread per agent**. +The broker's synchronous `bind`/`host_request` wrappers wait for channel replies: do not call such blocking interfaces from a rendering callback. Async model I/O can overlap across sessions; synchronous filesystem work still needs the existing worker boundary. One peer per app and account is an identity rule. The number of tasks and worker threads follows the runtimes and active operations above. -## 11. Verify one boundary at a time +## 11. Tests and remaining implementation -These checks were run for this documentation review: +[Broker tests](../crates/app-peers/tests/broker.rs) provide executable protocol examples: `a_persons_message_runs_while_the_system_agents_input_runs`, `a_lane_stop_leaves_the_other_lane_running`, `a_kernel_without_shared_history_is_refused_for_the_conversation`, and `removing_an_account_purges_its_recorded_peer_and_drops_the_record`. [Shell relay scenario tests](../crates/shell/src/host_tools/scenario_tests.rs) cover caller/tool/approval boundaries. Start with these when changing a conversation or executor path. -- Runtime setup with the existing clone hub, followed by `python3 tools/setup.py --check --cargo`: passed. -- `python3 tools/native_apps.py --check` and `python3 -m unittest discover -s rom/tests -p test_no_local_paths.py`: passed. -- Changed Markdown relative-file links and `git diff --check` across the five documentation worktrees: passed. -- `cargo test --locked -p octosense-kernel -p octosense-app-peers --features octosense-app-peers/octos-core,octosense-app-peers/ws`: passed the unit and scripted-connector suites. Real-kernel test functions early-return unless their binary environment variables are supplied; this review did not supply them and does **not** claim those integrations passed. +Run the unit and scripted-connector tests from the repository root: + +```sh +cargo test --locked -p octosense-kernel -p octosense-app-peers \ + --features octosense-app-peers/octos-core,octosense-app-peers/ws +``` -Use [broker tests](../crates/app-peers/tests/broker.rs) as executable examples: `a_persons_message_runs_while_the_system_agents_input_runs`, `a_lane_stop_leaves_the_other_lane_running`, `a_kernel_without_shared_history_is_refused_for_the_conversation`, and `removing_an_account_purges_its_recorded_peer_and_drops_the_record`. They demonstrate actual protocol behavior without a paid model. [Shell relay scenario tests](../crates/shell/src/host_tools/scenario_tests.rs) show caller/tool/approval boundaries; they were read, not executed in this review. +Optional real-kernel tests return early when their binary environment variables are absent; see the [app-peers test instructions](../crates/app-peers/README.md) before treating those as integration evidence. Visible UI, real-provider conversations and device behavior require separate runs. -Desktop GUI launch, real-provider turns, Android/OpenHarmony/iOS builds, ROM image builds and flashing are **unverified in this review**. `AGENT.md` prompt loading, automatic bundle triggers/skills, arbitrary script-implemented agent tools and a general app-to-system-agent RPC remain implementation gaps. Do not turn an architectural example into a claimed working workflow without checking its declarations and executor. +Remaining implementation work includes bundle `AGENT.md` prompt loading, automatic bundle triggers/skills, script-implemented agent tool dispatch and a general app-to-system-agent conversation RPC. Follow declarations through their executor before building a workflow around one of these paths. diff --git a/docs/architecture-walkthrough.zh-CN.md b/docs/architecture-walkthrough.zh-CN.md index ac80a9d8..c4064245 100644 --- a/docs/architecture-walkthrough.zh-CN.md +++ b/docs/architecture-walkthrough.zh-CN.md @@ -2,168 +2,243 @@ [English](architecture-walkthrough.md) | 简体中文 -本文面向了解 Rust 结构体、trait 和函数,但不熟悉 Agent 与 OctoSense 的开发者。阅读依据是 2026-10-01 检查的 OctoSense `c19da8d`,以及 Cargo 锁定的 octos `ae230ce0`。[架构参考](architecture.zh-CN.md)说明整体设计;本文沿着调用链、数据所有权与执行边界阅读实现。ADR 中的决定不代表所有步骤都已运行。 +本文沿着一条消息,阅读应用窗口、Shell、Agent 内核与工具执行器之间的调用。如果你了解 Rust,但刚接触 OctoSense 或 Agent,可以从这里开始。[架构参考](architecture.zh-CN.md)介绍整体设计,本文跟踪实现中的调用与所有权。依赖版本以 [Cargo.toml](../Cargo.toml) 和 [native-runtime.lock.json](../native-runtime.lock.json) 为准。ADR 记录设计决策,尚待实现的部分列在第 11 节。 -## 1. 先区分名字 +## 1. 先分清这些名称 -| 名称 | 在这里的含义 | +| 名称 | 本文中的含义 | | --- | --- | -| OctoSense | 桌面/Home Shell、应用和宿主服务;ROM 将 Home 与 Android 平台组件一起打包。 | -| Makepad | Rust UI、事件循环与渲染框架。 | -| Splash / Makepad Script | 受限 `main.splash` 应用使用的脚本 VM 和 UI 语言,不是独立的 Octoscript L0 解析器。 | -| Octoscript / Octoscript-Makepad | L0 卡片语言、检查/降级到运行时的工具和 Makepad 集成;`.card` 与 `main.splash` 的加载路径不同。 | -| octos | 负责模型调用、回合、工具、记录、记忆及 peer 协作的 Agent 内核,不是操作系统内核。 | -| Agent | 读取消息、选择已提供的工具、根据结果继续推理并回答的模型工作单元。模型输出本身不会执行应用操作。 | -| session / turn | session 标识会话及其状态;turn 是一次输入引起的执行,可包含多次模型和工具调用。 | -| peer / request context | peer 是持久协作身份;context 是该 peer 下的另一个会话,有独立记录、工作目录和子记忆命名空间。 | -| tool / host service | tool 是提供给模型的操作;host service 是处理应用或工具执行器请求的 Rust 实现。两者不会自动互相暴露。 | -| `AGENTS.md` / `AGENT.md` | 仓库贡献者规则 / 应用包的 Agent 指令文件。App Hub 可以校验后者,但 Shell 尚未将它装入 peer 提示词。 | +| OctoSense | 桌面/Home Shell、应用及其宿主服务。ROM 把 Home 与 Android 平台组件一起打包。 | +| Makepad | Rust UI、事件与渲染框架;事件循环更新控件树。 | +| Splash / Makepad Script | 隔离运行 `main.splash` 应用的脚本 VM 与 UI 语言;与 Octoscript L0 解析器分别实现。 | +| Octoscript / Octoscript-Makepad | L0 卡片语言、检查器、lowering 及 Makepad 集成,还提供应用运行时支持。`.card` 与 `main.splash` 有各自的加载路径。 | +| octos | Agent 内核,负责模型调用、回合、工具、对话记录、记忆与 peer 协作;这里的“内核”指 Agent 运行时。 | +| Agent | 读取消息、选择工具、消费结果并回答的模型工作单元。实际操作由工具执行器完成。 | +| Session / turn | Session 保存一次对话的身份与状态;turn 是响应一次输入的执行过程,可包含多次模型请求与工具调用。 | +| Peer / request context | Peer 是持久的协作 Agent 身份;context 是属于该 peer 的另一个 session,有独立记录、工作目录和子记忆命名空间。 | +| Tool / host service | Tool 是模型可选择的操作;host service 是应用或执行器调用的 Rust 服务。分别检查它们的授权与入口。 | +| `AGENTS.md` / `AGENT.md` | 前者指导仓库贡献者;后者是应用包的 Agent 指令文件。App Hub 会准入后者,但 Shell 尚未把它加载进 peer 提示词。 | -相关仓库是 [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow)、[App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub)、[Octoscript-Makepad](https://github.com/OctoSense-org/Octoscript-Makepad) 和 [octos](https://github.com/octos-org/octos)。分别读取各自的锁定版本,不要默认相邻 checkout 的 `main` 就是 Shell 使用的版本。 +相关仓库的导读:[Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/docs/junior-architecture-walkthrough/docs/CODE-WALKTHROUGH.md)、[App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/docs/junior-architecture-walkthrough/docs/CODE-WALKTHROUGH.md)、[Octoscript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad/blob/docs/junior-architecture-walkthrough/docs/architecture-walkthrough.md)、[octos](https://github.com/octos-org/octos/blob/docs/junior-architecture-walkthrough/docs/octosense-integration-walkthrough.md)。这些链接指向已发布的文档分支;运行时版本仍由使用方的依赖锁定文件控制。 -## 2. 从可执行入口找到应用宿主 +## 2. 从可执行入口读到应用宿主 -先读 [desktop/src/main.rs](../desktop/src/main.rs)、[phone/src/main.rs](../phone/src/main.rs),再读 [shell/src/lib.rs](../crates/shell/src/lib.rs)。Desktop 和 Home 是链接同一 Shell 的两个包;Home 还提供 Settings 与平台集成。ROM 打包 Home 和 Android 特权组件,并未另写一套 Rust Agent 架构。 +先打开 [desktop/src/main.rs](../desktop/src/main.rs)、[phone/src/main.rs](../phone/src/main.rs),再读 [crates/shell/src/lib.rs](../crates/shell/src/lib.rs)。Desktop 和 Home 链接同一个 Shell;Home 还提供 Settings 与平台集成。ROM 打包 Home 和特权 Android 服务,沿用同一套 Rust Agent 架构。 -应用启动选择来自 [native-apps.json](../native-apps.json)、[apps.rs](../crates/shell/src/apps.rs) 中的 `AppRegistry`,以及各产品的 `system-apps.json`: +应用启动方式来自 [native-apps.json](../native-apps.json)、[apps.rs 的 AppRegistry](../crates/shell/src/apps.rs) 与各产品的 `system-apps.json`: -| 应用形态 | 源码入口 | 实际执行方式 | +| 启动对象 | 代码路径 | 实际运行方式 | | --- | --- | --- | -| Rust 模块,如 Reference、Rinx | [module_host.rs](../crates/shell/src/module_host.rs) | 与 Shell 同进程;每个实例有脚本 isolate,但 Rust 内存仍共享。 | -| 原生进程应用,目前为受支持桌面上的 Terminal | [clients.rs](../crates/shell/src/clients.rs)、[hub.rs](../crates/shell/src/hub.rs)、[process-apps](../crates/process-apps/src/lib.rs) | 子进程通过经过认证的 Makepad hub 交换帧、输入和 AI-bus 消息。此连接不同于 octos 协议连接。 | -| 受限脚本应用 | App Hub 的 `CARD_MODULE`,从 `apps.rs` 接入 | 校验应用包后创建嵌套的受限 Splash VM;每个包不需要编译一个 Rust 可执行文件。 | -| L0 glance 卡片 | [glance.rs](../crates/shell/src/glance.rs)、[glance_chat.rs](../crates/shell/src/glance_chat.rs) | 运行时检查、转换并渲染卡片,宿主提供数据和聊天;卡片本身不是新 peer。 | +| 原生 Rust 模块,如 Reference、Rinx | [module_host.rs](../crates/shell/src/module_host.rs):创建模块,注入作用域句柄、助手和存储接口 | Rust 代码与 UI 在 Shell 进程内运行;每实例有脚本 isolate,Rust 内存仍在同一进程。 | +| 原生进程应用,如受支持桌面上的 Terminal | [clients.rs](../crates/shell/src/clients.rs)、[hub.rs](../crates/shell/src/hub.rs)、[process-apps](../crates/process-apps/src/lib.rs) | 子进程经认证的 Makepad hub socket 交换帧、输入与 AI bus 消息。同一 socket 的 `octos_peer` 封装还支持助手连接(第 5 节);当前随产品提供的进程应用未请求 `agent.octos` 服务。 | +| 隔离脚本应用 | `apps.rs` 进入 App Hub 的 `CARD_MODULE` | Card runner 准入应用包,创建受限的嵌套 Splash VM;capability 限制宿主服务和平台 API。每个包无需编译 Rust 可执行文件。 | +| Glance 卡片 | [glance.rs](../crates/shell/src/glance.rs)、[glance_chat.rs](../crates/shell/src/glance_chat.rs) | L0/L1 `source` 卡片经检查并结合宿主数据 lower 到运行时;Splash `script` 卡片在发布者策略下运行交互逻辑。`notify` 增加通知,UI 用 `glance::dismiss` 移除,应用用 `glance.withdraw` 撤回。聊天通向发布者的 peer。 | -具体命令见[桌面](../desktop/README.zh-CN.md)、[Home](../phone/README.zh-CN.md)、[ROM](../rom/README.zh-CN.md)及[系统应用](../apps/README.zh-CN.md)。下面从仓库根目录运行的启动/构建命令已核对源码,但**本次未验证实际启动、GUI 或设备构建**: +各产品运行细节见[桌面](../desktop/README.zh-CN.md)、[Home](../phone/README.zh-CN.md)、[ROM](../rom/README.zh-CN.md)和[系统应用](../apps/README.zh-CN.md)。以下构建/启动配方 **unverified(未验证)**,平台前置条件见产品 README。在仓库根目录运行: ```sh python3 tools/setup.py --hub /path/to/existing-clones python3 tools/setup.py --check --cargo cargo run --release -p octosense +# 可选的进程内 Rust 示例: MAKEPAD_WM_TEST_APP=reference cargo run --release -p octosense --features app-reference -- --module reference +# 启用内核集成;二进制应来自 Cargo.toml 锁定的 octos 版本: OCTOS_APP_CORE_BIN=/path/to/pinned/octos \ cargo run --release -p octosense --features octos-core ``` -内核二进制应来自 `Cargo.toml` 锁定的 octos 版本,`OCTOS_APP_CORE_BIN` 必须指向文件;这里不会查找 `PATH`。真实对话还要求用户在宿主拥有的 AI providers 面板配置提供方和模型。编译 Rust 不会自动配置凭据。自动化 UI 检查使用产品 README 的隐藏窗口方式。 +真实对话还需要在 AI providers 的宿主确认面板配置提供方、模型与凭据。`OCTOS_APP_CORE_BIN` 指定一个文件;此启动器不会搜索 `PATH`。自动 UI 工作使用产品 README 中的隐藏窗口方式。 -脚本应用的 Design Flow `tools/octo` 是 Python CLI,包装 App Hub 的 `card-host` 和 `hub`,与 octos Agent 内核无关。`card-host` 可检查受限 UI/策略,但没有安装 Shell 的 Mail、Calendar、提供方或 peer 服务。这些集成必须在 Shell 中验证;`hub check` 通过不代表 Agent 回合成功。 +脚本应用使用 Design Flow 的 Python CLI `tools/octo`,它封装 App Hub 的 `card-host` 与 `hub`。在 Design Flow 检出目录运行 `tools/octo run /path/to/bundle`(启动配方未验证)。独立 runner 检查隔离 UI 与策略;Mail、Calendar、提供方与 peer 服务由 Shell 注册,因此集成测试需要 Shell。`hub check` 通过说明包满足准入约定。 -## 3. 谁拥有内核 +## 3. 找到内核的所有者 -阅读 [ai-host/src/lib.rs](../crates/ai-host/src/lib.rs),然后读 [kernel/src/lib.rs](../crates/kernel/src/lib.rs)、[launch.rs](../crates/kernel/src/launch.rs)、[kernel.rs](../crates/kernel/src/kernel.rs) 和 [router.rs](../crates/kernel/src/router.rs)。 +依次阅读 [ai-host/src/lib.rs](../crates/ai-host/src/lib.rs)、[kernel/src/lib.rs](../crates/kernel/src/lib.rs)、[launch.rs](../crates/kernel/src/launch.rs)、[kernel.rs](../crates/kernel/src/kernel.rs) 和 [router.rs](../crates/kernel/src/router.rs)。 -1. Shell 调用 `ai_host::start` 注册服务、配置内核来源。`model.complete` 是单次模型请求,不会创建 peer 或工具循环。 -2. 首个获准使用内核的消费者调用 `Core::connect`,得到逻辑 `Connection`;后续消费者共享同一代内核。 -3. `launch::resolve` 选择桌面子进程、Android 包装为 `liboctos.so` 的可执行文件,或 OpenHarmony 内嵌服务;iOS 此处没有内核。 -4. `kernel::supervise` 拥有运行中的进程/任务和消息泵;`Router` 在唯一物理连接上关联消费者请求 ID 与会话事件。 -5. OUP 使用 JSON-RPC 请求和异步通知。默认通过 stdio 传输逐行 JSON;开启 Talk to Octos 后改用宿主管理的本地 WebSocket,不会为每个客户端另起一个内核。 -6. 提供方变更会重启内核代次,消费者必须重连、重新绑定。丢弃一个 Rust `Connection` 不等于删除 peer 记忆。 +1. Shell 调用 `ai_host::start` 注册服务、配置内核来源。`model.complete` 是一次提供方请求;peer 与工具循环走另一条路径。 +2. 首个获授权的使用方调用 `Core::connect`,得到逻辑 `Connection`;后续使用方共享同一内核代际。 +3. `launch::resolve` 选择桌面子进程(`OCTOS_APP_CORE_BIN` 或显式程序)、Android 打包的 `liboctos.so` 可执行文件,或 OpenHarmony 内嵌服务。iOS 在这里没有内核。 +4. `kernel::supervise` 持有运行中的进程/任务和帧循环。`Router` 在一条物理连接上关联使用方请求 ID 与 session 事件。 +5. OUP 协议使用 JSON-RPC 与异步通知。普通模式经 stdio 传输逐行 JSON;启用 Talk to Octos 后改用宿主管理的回环 WebSocket,客户端共享该内核。 +6. 提供方变化会重启代际,使用方需重连并重新绑定。Peer 记忆的生命周期长于 `Connection`。 -ROM 的 Android 特权“agent”执行经过允许的平台操作,不运行系统 LLM 会话。这两个“agent”必须分清。 +ROM 的特权 Android 服务也称“agent”,负责通过 Android bridge 执行允许的平台操作;系统 LLM 对话运行在 octos 中。 -## 4. 跟随系统聊天的一条消息 +## 4. 跟踪一条系统聊天消息 -读 [system_chat/mod.rs](../crates/shell/src/system_chat/mod.rs)、[session.rs](../crates/shell/src/system_chat/session.rs)、[link.rs](../crates/shell/src/system_chat/link.rs) 和 [system_tools.rs](../crates/kernel/src/system_tools.rs)。 +阅读 [system_chat/mod.rs](../crates/shell/src/system_chat/mod.rs)、[session.rs](../crates/shell/src/system_chat/session.rs)、[link.rs](../crates/shell/src/system_chat/link.rs) 和 [system_tools.rs](../crates/kernel/src/system_tools.rs)。 -助手面板发送 `Command` 给工作线程;`Driver` 打开 `_main:api:octosense#system`、读取历史并启动回合。事件更新聊天模型,`SignalToUI` 唤醒 Makepad 绘制快照。绘制线程不会同步等待模型完成。 +助手面板向工作线程发送 `Command`。`Driver` 打开 `_main:api:octosense#system`、读取历史并启动回合。收到的事件更新聊天模型,`SignalToUI` 唤醒 Makepad 事件循环绘制快照。 -系统 Agent 是 `_main` profile 下的会话。宿主通过 `session/tool_list/set` 缩小其内核工具集;`SYSTEM_AGENT_TOOLS` 包括 `peer_list`、`peer_send_input`、`peer_gather`、`peer_respond`。用户开启命令执行后,正常路径是 Shell 的 `terminal.run` 及其审批界面,而不是 octos 内置 `shell`。 +系统 Agent 是 `_main` profile 的一个 session。宿主通过 `session/tool_list/set` 限定其内核工具;`SYSTEM_AGENT_TOOLS` 包含 `peer_list`、`peer_send_input`、`peer_gather` 和 `peer_respond`。用户开启命令执行后,它通过 Shell 的 `terminal.run` 与审批 UI 执行命令;octos 内置 `shell` 不在其工具列表中。 -[agents.rs](../crates/shell/src/agents.rs) 的 `agents.list` 发现应用 Agent 及其状态,`agents.ask` 请求首次同意。后者不是通用的“应用调用系统 Agent”聊天 API,模型也不能替用户同意。 +[agents.rs](../crates/shell/src/agents.rs) 提供两个宿主工具:`agents.list` 查询应用 Agent 及可用状态;`agents.ask` 打开首次同意面板并等待可用的 peer slug。成功后系统 Agent 用 `peer_send_input` 提交任务;ask 调用只准备访问。首次同意由用户控制。 -## 5. 一个应用 peer,两条并行通道 +## 5. 一个应用 peer,两条对话通道 -先读 [contract.rs](../crates/app-peers/src/contract.rs),再读 [broker.rs](../crates/app-peers/src/broker.rs):`OctosAppService` 是应用拿到的受限助手句柄;`OctosContext` 是对话/请求句柄;`ContextSpec` 携带宿主认证的账号、实例和服务授权;`Broker(Arc)` 实现连接、peer、context 与在途请求管理。 +先读 [app-peers/src/contract.rs](../crates/app-peers/src/contract.rs),再读较大的 [broker.rs](../crates/app-peers/src/broker.rs): -原生模块经 [hosted.rs](../crates/app-peers/src/hosted.rs) 和 [injection.rs](../crates/app-peers/src/injection.rs) 获得服务。脚本应用经 [contained.rs](../crates/ai-host/src/contained.rs) 接入同一 broker。manifest 的助手服务、`agent` 块或 `tools.json` 使应用具备 Agent 资格,但仍需内核、同意及有效账号。 +- `OctosAppService`:应用拿到的作用域助手句柄。 +- `OctosContext`:对话/请求句柄;`call(ContextOp, EventSink)` 启动操作并交付 `ContextEvent`。 +- `ContextSpec`:宿主认证的账号、实例与已授权服务名。 +- `Broker`:Shell 对接口的实现,通过 `Arc` 持有连接、peer、context 与在途请求。 -`card.os.news` 是 broker 使用的应用身份,不一定是内核生成的 peer slug。`peer/prepare` 返回 slug、会话和宿主凭据,应使用返回值。peer 按应用与账号区分;无账号应用使用 `device`,Mail 使用宿主报告的已登录账号。`ensure_peer` 恢复记录、核验命名空间并注册工具,成功后才执行回合。 +原生模块通过 [hosted.rs](../crates/app-peers/src/hosted.rs) 和 [injection.rs](../crates/app-peers/src/injection.rs) 获得句柄;隔离应用通过 [contained.rs](../crates/ai-host/src/contained.rs) 访问相同 broker。脚本 manifest 声明助手服务或 `agent` 块,或包内包含 `tools.json`,就具备 Agent 资格;运行还需要内核、用户同意及适用的有效账号。 -系统 Agent 调用 `peer_send_input` → octos 发出 `peer/input` → Shell broker 校验和排队 → broker 以 input ID 在 peer 会话调用 `turn/start`。因此是 Shell 驱动应用回合,并非内核收到消息就绕过 Shell 执行。 +原生进程客户端使用 [peer_link](../crates/shell/src/peer_link/mod.rs):`OctosPeer` 消息封装为 `octos_peer`,共用已认证的 hub socket。Shell 根据自己启动的客户端确定应用和实例,检查 `native-apps.json` 的确切 `agent.octos` 授权与同意状态,再把 session、history、turn、interrupt 操作交给该应用的 broker。进程内模块也能打开同一客户端,由 `module_host` 认领暂存的连接;注入的 `OctosAppService` 是另一种适配器。进程退出会取消在途工作并关闭请求 context,保留持久 peer;结果不确定的写入返回 `outcome_unknown`。 -人类通过 `open_conversation` 打开带 `share_history` 的 request context,形成另一条通道。两条通道的 transcript 和回合状态独立;模型只读地看到另一条通道的有限近期文本。多个聊天界面可以打开同一 peer 的不同 conversation context。普通 `open_context` 用于 Rinx mini app 等客户端工作,不共享历史。context 有自己的内核会话,但不是另一个应用 peer。 +`card.os.news` 是 broker 的应用身份;内核的 peer slug 由 `peer/prepare` 返回,连同 peer session 和宿主凭据一起使用。Peer 按应用与账号区分:无账号应用使用 `device`,Mail 使用宿主报告的登录账号。`ensure_peer` 恢复记录的 peer,核对命名空间并注册工具,然后才运行回合。 -`driver_of` 与 `take_over` 保证一个 peer 的系统输入队列只有一个 broker 驱动,避免每个应用窗口重复执行同一 `peer/input`。人类 context 的回合可以同时运行。 +```mermaid +sequenceDiagram + participant H as 用户 + participant S as 系统 Agent session + participant K as octos + participant B as Shell broker + participant A as 应用 peer session + participant C as 应用对话 context + S->>K: peer_send_input(peer, task) + K->>B: peer/input 通知 + B->>B: 检查账号、同意与工具;输入排队 + B->>K: peer session 上 turn/start,携带 input id + K->>A: 执行系统通道回合 + H->>B: Ask app:ContextOp::Turn + B->>K: peer/context/open,share_history;turn/start + K->>C: 执行用户通道回合 + A-->>K: 回合完成 / peer 结果 + K-->>S: 黑板结果可由 peer_gather 读取 + C-->>B: 流式事件与完成 + B-->>H: 应用对话 / 卡片聊天回复 +``` + +应用 peer session 是**系统通道**;`open_conversation` 创建带 `share_history` 的请求 context,作为**用户通道**。两者各有记录和回合状态,有限的另一通道近期文本以只读形式补充。多个用户界面可以创建同一 peer 的多个对话 context。`open_context` 用于无历史共享的客户端工作,例如 Rinx 小程序。每个请求 context 是独立的内核 session,归属于原来的应用 peer。 -## 6. 人在哪里说话,回答回到哪里 +多个原生实例共享 peer 时,broker 的 `driver_of` / `take_over` 选择一个 broker 驱动系统通道输入队列,避免多个窗口重复执行 `peer/input`。用户 context 的工作可以与当前系统通道回合并发。 -| 入口 | 实现 | +## 6. 用户在哪里提问,结果返回哪里 + +| 入口 | 实现与行为 | | --- | --- | -| 系统助手面板 / F8 | `system_chat` 使用系统会话;系统委派任务引发的应用问题也显示在此。 | -| “Ask ” / Shift+F8 | [app_chat](../crates/shell/src/app_chat/mod.rs) 调用 `agents::conversation`,订阅两条通道并合并历史;Send 在人类 context 启动回合。 | -| 原生应用自己的聊天 | 注入的 `OctosAppService::open_conversation`,应用渲染事件。 | -| 脚本应用自己的聊天 | 通过 `host.request` 调用精确授权的四个 `octos.*` 服务。News/Mail/Calendar 自身未声明这些调用,但 Shell 仍可驱动其 Agent。 | -| 卡片中的聊天 | `sys.chat` → [l0-chat](../crates/l0-chat/src/lib.rs) 与 [glance_chat.rs](../crates/shell/src/glance_chat.rs),校验发布者后绑定拥有该卡片的应用。 | +| 系统助手面板,F8 | `system_chat` 使用系统 Agent 的 session;系统委派工作产生的问题也在这里显示。 | +| “Ask ”,Shift+F8 | [app_chat/mod.rs](../crates/shell/src/app_chat/mod.rs) 经 `agents::conversation` 订阅两条通道并合并历史;发送消息启动用户 context 回合。 | +| 原生应用自己的聊天 | 调用注入的 `OctosAppService::open_conversation`,由应用绘制事件。 | +| 脚本应用自己的聊天 | 经 `host.request` 调用确切获授权的 `octos.session.open`、`octos.session.history`、`octos.turn.start`、`octos.turn.interrupt`。随产品提供的系统应用 Agent 由 Shell 驱动,其脚本无需声明这些调用。 | +| 已发布卡片中的聊天 | `sys.chat` 经 [l0-chat](../crates/l0-chat/src/lib.rs) 与 [glance_chat.rs](../crates/shell/src/glance_chat.rs) 到达发布者的 Agent;宿主核对卡片归属。 | -目前手机触摸导航还没有打开 Ask 面板的对应入口;应用自己的聊天或已发布卡片的聊天是不同入口。Ask 面板的 Stop 只停人类通道;另一个明确的按钮停系统任务。底层 conversation 的 `ContextOp::Interrupt` 范围更大,可中断两条通道,不能把所有 Stop 混为一谈。隐藏面板保留 context/订阅;切换应用或撤销权限才关闭。 +手机触控导航尚无打开 Ask-app 面板的对应控件;应用自己的聊天与卡片聊天是另外的入口。Ask-app 面板的 Stop 中断用户通道,“Stop the system agent's task” 中断系统通道。底层 `ContextOp::Interrupt` 范围更大,可以中断两条通道。隐藏面板保留 context 和订阅;切换应用或撤销访问会关闭它。 -Shell 将自己的输入动作标为 `TurnTrigger::Person`;脚本 `octos.turn.start` 可携带 `trigger`/`from`,但其 `trigger: "person"` 只成为 `AppSaysPerson`。聊天中的人物标签不证明宿主看到了真实用户操作,也不会解锁仅限用户主动发起的审批规则。 +Shell 将聊天输入动作标为 `TurnTrigger::Person`。脚本调用 `octos.turn.start` 可传 `trigger` / `from`,但 `trigger: "person"` 被记录为 `AppSaysPerson`;脚本标签不能作为可信用户动作来匹配审批规则。 -工具结果先回到发起它的应用回合,供模型继续处理。人类 context 的最终事件通过其 event sink 回到聊天界面;系统委派回合的结果进入 peer blackboard,系统 Agent 用 `peer_gather` 获取并向用户总结。 +结构化工具结果回到发起它的应用回合。用户 context 的最终事件经其 event sink 回到对应界面;系统委派回合的结果写入 peer 黑板,由系统 Agent 获取并整理回答。 -## 7. 将工具声明追到真正的 Rust 实现 +## 7. 从工具声明追到 Rust 执行器 -读 [script_apps.rs](../crates/shell/src/host_tools/script_apps.rs)、[relay.rs](../crates/shell/src/host_tools/relay.rs) 和 [host_tools.rs](../crates/app-peers/src/host_tools.rs)。以 Calendar 的 `calendar.events` 为例: +阅读 [host_tools/script_apps.rs](../crates/shell/src/host_tools/script_apps.rs)、[relay.rs](../crates/shell/src/host_tools/relay.rs)、[app-peers/host_tools.rs](../crates/app-peers/src/host_tools.rs)。以 Calendar 的 `calendar.events` 为例: -1. [tools.json](../apps/calendar/bundle/tools.json) 声明 schema、风险、共享及实现方式;App Hub 校验摘要和规则。 -2. `from_bundle` 读取已准入声明;`install` 安装 catalog 项和 `HostServiceExecutor`。 -3. 驱动 peer 的 broker 经 `peer/tools/register` 注册精确工具集。 -4. 模型请求调用后,octos 发出 `peer/tool/call`;broker 附上真实调用者、账号、context 并交给 Shell `ToolHost`。 -5. `Relay::handle` 检查授权、同意、账号状态、输入 schema、大小及预算,需要时走 Shell 审批。 -6. 执行器以工具所属应用身份调用 [Calendar 服务](../apps/calendar/host-service/src/lib.rs)。回复经队列回来,输出也经过校验,`ToolReply` 最多发送一次 `peer/tool/result`。 -7. 模型读取 JSON 结果,回答或继续调用其他已授权工具。 +1. [tools.json](../apps/calendar/bundle/tools.json) 声明 schema、风险、共享与实现方式;App Hub 校验应用包并计算摘要。 +2. `script_apps::from_bundle` 加载准入的声明;`install` 加入 relay catalog,并安装 `HostServiceExecutor`。 +3. 驱动 peer 的 broker 用 `peer/tools/register` 注册精确工具列表;模型才能请求这些工具。 +4. octos 发出 `peer/tool/call`,broker 盖上真实调用方、账号与 context,交给 Shell 的 `ToolHost`。 +5. `Relay::handle` 检查授权、同意、账号、输入 schema、大小与调用预算;需要审批的调用进入下述路由器。 +6. 执行器以**工具所属应用**的身份调用 Calendar 宿主服务,读取 [Calendar 存储](../apps/calendar/host-service/src/lib.rs)。结果经回复队列返回,检查输出 schema/大小后,`ToolReply` 最多发送一次 `peer/tool/result`。 +7. 模型消费 JSON 结果并继续回合,输出回答或请求另一个获授权工具。 -声明不等于实现。`implemented_by: "host-service"` 需要存在对应服务且所属应用有权限;`implemented_by: "app"` 目前虽能准入,Card runner 尚未实现其脚本执行器,会返回不可用。复制 `tools.json` 或 gate 通过都不会补齐服务代码。 +`implemented_by: "host-service"` 需要存在可调用的服务;`implemented_by: "app"` 虽可作为元数据准入,但 Card runner 尚无脚本工具执行器,会返回 unavailable。声明文件和准入检查分别描述、验证接口;真正操作需要执行器代码。 -## 8. “读取应用数据”有几种完全不同的含义 +[host_tools/mod.rs](../crates/shell/src/host_tools/mod.rs) 将 broker 线程的调用放入 inbox,由 UI 事件循环泵送并排队回复: -| 数据 | 访问方式 | +| 工具路线 | 执行边界 | | --- | --- | -| 应用账号目录 | [app_storage](../crates/shell/src/app_storage/mod.rs) 和 `agent_workspace` 将新 peer 的 cwd 绑定到获准目录;内核文件工具仍需授权。 | -| context 读取账号文本文件 | Shell 的 [files.list/read/search](../crates/shell/src/host_tools/files.rs),目前仅 Unix、需同意和可用 workspace;有读取上限,拒绝符号链接并隐藏兄弟 context。这不是 SQLite 查询 API。 | -| 人类对话读取父账号目录 | `storage.agent_workspace: "account"` 时请求 `read_parent`,父目录只读、写入仍限自身 context;普通客户端 context 不自动拥有此能力。 | -| 宿主服务数据库或远端账号 | 必须经声明且实现的工具访问;workspace 不会挂载所有服务数据库或泄露凭据。 | -| 对话历史和 Agent 记忆 | octos session/context 及 `app//acct-`,不同于应用业务数据。 | -| 机密 | 宿主的 secret store 和输入面板,不在脚本状态或 Agent workspace。 | +| 隔离应用,`implemented_by: "host-service"` | `HostServiceExecutor` 调用准入的所属应用 Rust 服务。 | +| 原生模块 | `OctosAppService::set_tool_executor` 注册的回调。 | +| 原生进程 | `peer_link` 经认证的 hub socket 发送工具请求;仍需注册与授权。 | +| 系统 `terminal.run` | 开启 Command execution 后,Shell 经 AI bus 在可见 Terminal 中输入已批准的命令。 | +| `files.list/read/search` | Unix 上的 Shell 执行器,范围为调用方允许访问的账号工作目录。 | +| `dev.run` | Shell 执行器,仅提供给开发者模式覆盖的 peer。 | +| Toolbox 工具 | 已注册的工具箱执行器/工作流,需要 `toolbox-peers` feature 与应用授权。 | + +### 审批顺序 + +首次 Agent 同意、工具授权和逐次调用审批是三个独立检查。[approvals/router.rs](../crates/shell/src/approvals/router.rs) 按以下顺序处理审批请求: + +1. 外部客户端的回合由该客户端处理;Shell 不回答其提示,也不使其过期。 +2. 开发者模式自动批准覆盖应用的请求,包括 `auto_approvable: false` 和 `confirm: app`。 +3. `confirm: app` 交给工具所属应用注册的确认面板,显示调用方;常设规则不会回答。若应用未在 `app_wait_s` 内注册面板,请求被拒绝。 +4. `auto_approvable: false`、结果未知,以及被标为外部连接的调用,要求用户决定。 +5. 用户预先设置的常设规则可决定符合条件的请求;由收到的内容触发的运行默认跳过,除非规则明确包含。 +6. 其余请求显示 Shell 确认面板;同一系统任务的调用可以合并展示。 + +决定只交付一次,并记录到仅所有者可读写的审计日志;自动决定还产生通知。Shell 持有的宿主连接待答请求在 `OCTOSENSE_PROMPT_DEADLINE_SECS`(默认十分钟)后以拒绝过期。宿主工具审计保存参数摘要而非原始参数。模型的文本回复或 `peer_respond` 无法批准工具调用。 -Calendar 服务在其宿主目录保存 `calendar/events.json` 并通过工具操作;News 暴露 `news.list/read`。Mail 当前 Agent **只声明 `mail.notify`**:Mail UI 能读信和发信不表示模型也能调用。旧 AppCard personal-data 导入器不会自动同步今天 Mail 的存储。 +## 8. “访问应用数据”对应哪些存储 -账号目录的 SHA-256 标签与 peer 记忆的 FNV 标签是不同的兼容标识,不能互换。登出暂停访问并保留数据;删除账号/卸载还请求 `peer/purge`,遇到忙 peer 会重试。恢复已有 peer 时不能静默更换已记录的 workspace。 +| 数据 | 应用 Agent 的访问路线 | +| --- | --- | +| 应用账号目录 | [app_storage](../crates/shell/src/app_storage/mod.rs) 与 `ToolHost::agent_workspace` 将新 peer 的 cwd 绑定到允许的目录;内核文件工具仍需授权。 | +| 请求 context 中读取账号文本文件 | [files.rs](../crates/shell/src/host_tools/files.rs) 的 `files.list/read/search`,当前限 Unix,要求同意和可用工作目录;限制大小,拒绝符号链接穿越,隐藏同级 context。SQLite 数据需另设服务接口。 | +| 用户对话的父账号目录 | 只有 `storage.agent_workspace: "account"` 允许时才请求 `read_parent`。父目录只读,写入留在 context 自己的目录;普通客户端 context 不自动获得此访问。 | +| 宿主服务数据库或远程账号 | 通过该服务实现的具体工具;工作目录权限不包含所有宿主数据库与远程凭据。 | +| Agent 记录与记忆 | octos session/context 和 `app//acct-` 命名空间,与应用业务数据分别存放。 | +| 机密 | 宿主机密存储和确认面板;不进入 Agent 工作目录或脚本状态。 | + +Calendar 的宿主目录保存 `calendar/events.json`,通过 `calendar.*` 访问。News 提供 `news.list`、`news.read` 和 `news.notify`。Photos、Maps、Camera、YouTube 仅提供各自的 `.notify`,经 [glance_notice.rs](../crates/shell/src/glance_notice.rs) 发布共享通知卡片。AI providers 没有应用 Agent。Mail 当前只声明 **`mail.notify`**;UI 中的读信和发信接口尚未作为 Agent 工具开放。旧 AppCard 个人数据导入器也不会自动同步当前 Mail 存储。 -## 9. 跨应用调用与请求帮助 +账号目录名使用 SHA-256 派生 tag,peer 记忆名称使用 broker 的 FNV 派生 tag;它们是不同的兼容标识。退出登录会暂停访问并保留数据;移除账号/卸载还会请求 `peer/purge`,忙碌时重试。恢复 peer 时,其已保存的工作目录不能悄悄改变。 -**委派**:系统 Agent 用 `peer_send_input` 请求已有应用 peer 做事,再获取结果;Shell 驱动该回合,并未新建一个进程。 +## 9. 跨应用工作与求助 -**直接调用另一个应用的工具**:`Catalog::owner_of` 解析 owner;`may_call` 要求工具确实存在、`shareable: true` 以及该调用者的授权(显式开发模式另有规则)。脚本 `agent.tools` 中带点名称和原生清单 grants 表达请求;relay 调用 owner 执行器,不一定经过 owner 的模型。当前 owner 解析覆盖原生、工具箱和 `os.`,不是任意商店应用发现机制。还必须通过 App Hub 的 `HostLimits.offered_tools` 准入;默认不提供的 `mail.send` 等名字不能仅靠写入 manifest 获准。 +**委派任务:**系统 Agent 用 `peer_send_input` 请求现有应用 peer 工作,再获取结果。Shell 驱动该应用回合,peer 身份可以跨进程生命周期保留。 -**问题或系统设施**:应用 Agent 只有获得 `ask_user_question` 才能使用它。[questions/mod.rs](../crates/shell/src/questions/mod.rs) 按回合来源将问题放到系统聊天或应用聊天,最终由人在 Shell 界面回答。此路由不是获取系统 Agent 权限的方法。Shell 没有给每个受限应用通用 `ask_system_agent` API 或任意 peer 工具。[系统工具箱](../crates/toolbox/README.md) 是工具/工作流服务,调用它也不等于与系统 Agent 聊天。 +**直接调用另一应用的 API 工具:**`Catalog::owner_of` 找到工具所属应用;通常 `may_call` 同时要求已有声明、`shareable: true` 和调用方授权,显式开发者模式规则另行处理。脚本 manifest 通过 `agent.tools` 请求带点的工具名,原生应用通过审核过的条目获得授权。App Hub 的 `HostLimits.offered_tools` 还必须提供请求的名称;默认未提供任意名称(例如 `mail.send`)。Relay 随后调用所属应用的执行器,无需询问该应用的模型,数据由执行器控制。当前 owner 解析覆盖原生命名空间、toolbox 与 `os.`;任意已安装商店应用的发现尚未实现。 -系统 Agent 的 `peer_respond` 不能代替用户批准应用操作。审批与问题使用不同协议消息和宿主句柄;超时只会拒绝/谢绝,不会把沉默当成同意。 +**提问或使用系统设施:**应用 Agent 可调用获授权的 `ask_user_question`。[questions/mod.rs](../crates/shell/src/questions/mod.rs) 按回合来源路由:系统委派工作在系统聊天中提问,用户/应用回合在应用对话中提问,由用户在 Shell 界面回答。系统设施以明确授权的工具提供,例如 [toolbox](../crates/toolbox/README.md) 工作流。通用的应用到系统 Agent 对话 RPC 尚未实现。`peer_respond` 处理 peer 协作;审批消息使用单独的宿主回答句柄。 -## 10. 映射到 Rust、线程和 Tokio +## 10. 映射到 Rust 的实际执行模型 -`async fn` 返回 future;poll 推进执行,直到等待 I/O。Tokio task 是被调度的 future,一个 OS 线程可以轮流 poll 很多 task。持久 session/peer 可以比当前处理它的所有 task 活得更久。 +Peer 是持久身份与状态;回合执行期间使用运行时任务,peer 在这些任务结束后仍存在。分别阅读所有权与调度边界: -| 层 | 实际执行方式 | 源码 | +| 层 | 实际执行模型 | 源码 | | --- | --- | --- | -| Makepad Shell | UI 事件循环,绘制、模块事件和 relay pump | `module_host.rs`、`host_tools/mod.rs` | -| 系统聊天 | 普通 `std::thread`;命令/快照,通过 waker/unpark 轮询接收 | `system_chat/mod.rs`、`link.rs` | -| Shell 内核服务 | 懒创建 Tokio runtime,**2 个 worker、8 MiB 栈**;一代 supervisor 拥有传输与生命周期 | `kernel/src/lib.rs`、`kernel.rs` | -| 应用 broker | **每次 `Broker::new` 创建 1-worker runtime**;连接、请求、重试与期限任务;多个 broker 可共享同一 peer | `app-peers/src/broker.rs` | -| OpenHarmony 内嵌内核 | 宿主 runtime 上 spawn `serve_io`,通过 `tokio::io::duplex` 通信 | `kernel.rs::start` | -| octos OUP 回合 | 准入后 spawn `run_standalone_turn`,内部模型处理和进度/心跳还有其他任务 | octos `crates/octos-cli/src/api/ui_protocol_transport.rs` | -| octos 输出 | WebSocket 为异步 writer task;stdio/内嵌为有界同步队列和普通 writer 线程 | 同上 | -| 宿主服务/文件执行器 | 随服务而异:UI pump、回调、回复队列、阻塞工作线程;不是统一每应用一个 Tokio task | `files.rs`、App Hub `services.rs`、各服务 | +| Makepad Shell | UI 事件循环,绘制、事件分发、宿主工具 relay 泵送 | `module_host.rs`、`host_tools/mod.rs` | +| 系统聊天 | 普通 `std::thread`,交换命令与快照;`link::poll_for` 用 waker/unpark 轮询内核接收 | `system_chat/mod.rs`、`link.rs` | +| Shell 内核服务 | 惰性创建 Tokio runtime:**2 个工作线程,8 MiB 栈**;每代一个 supervisor task 持有传输与进程生命周期,另有 I/O task | `kernel/src/lib.rs::Inner::runtime`、`kernel.rs::supervise` | +| 应用 broker | **每次 `Broker::new` 创建 1 个工作线程的 runtime**,运行连接泵送、请求 future、重试和截止任务;多个 broker 可共享一个 peer | `app-peers/src/broker.rs` | +| OpenHarmony 内嵌内核 | 在宿主 runtime 上 spawn `serve_io`,经 `tokio::io::duplex` 通信 | `kernel.rs::start` | +| octos OUP 回合 | 已 spawn 的编排任务先在 `oneshot` 启动屏障等待活跃回合准入;成功后 `run_standalone_turn` 再 spawn Agent 处理与辅助任务 | 锁定 octos 的 `crates/octos-cli/src/api/ui_protocol_transport.rs` | +| octos 传输出口 | WebSocket 使用异步 writer task;内嵌/stdio 使用有界同步队列和普通 writer 线程 | 同一 octos 文件 | +| 宿主服务/文件执行器 | 按服务使用 UI 泵送、回调/回复队列或处理阻塞操作的工作线程 | `host_tools/files.rs`、App Hub `services.rs`、各应用服务 | + +```mermaid +flowchart LR + UI["Makepad UI 线程"] --> CMD["系统聊天 std 线程"] + UI --> B["Broker runtime:请求与连接任务"] + CMD --> C["Kernel Connection 通道"] + B --> C + C --> SUP["内核服务 supervisor task"] + SUP <-->|"stdio 或宿主 WebSocket"| OUP["octos 协议分发器"] + OUP --> T1["系统通道回合 task"] + OUP --> T2["用户 context 回合 task"] + T1 --> TOOL["工具 future 等待宿主回复"] + TOOL --> B + B --> Q["Shell relay 队列"] + Q --> UI +``` + +`mpsc` 是多发送方邮箱,`oneshot` 交付一次关联回复,`watch` 保存最新的生命周期/就绪状态。Broker 的请求 ID 对应 `oneshot` sender;连接循环用 `tokio::select!` 同时处理进出消息。内核 supervisor 选择控制消息、内核输出与进程退出。`Arc` 共享所有权,`Weak` 避免延长已关闭 broker/context 的生命周期,代际/epoch 检查拒绝旧账号或连接的迟到回复。 -`mpsc` 是多发送者邮箱,`oneshot` 是一次对应回复,`watch` 是最新生命周期/就绪状态。broker 用请求 ID 找到 `oneshot`,其连接循环用 `select!` 接收双向消息;supervisor 同时等待控制消息、内核输出与退出。`Arc` 共享所有权,`Weak` 避免让已关闭对象永久存活,generation/epoch 丢弃旧账号或旧连接的迟到回复。 +Broker 同步 `bind` / `host_request` 会等待通道回复,不应在绘制回调中调用。不同 session 的异步模型 I/O 可重叠,同步文件工作仍走已有的工作线程边界。每应用/账号一个 peer 是身份规则;task 和线程数量由上表的 runtime 与活跃操作决定。 -同步 `bind`/`host_request` 会等待 channel,不能在绘制回调中阻塞调用。模型异步 I/O 可以并发,阻塞文件操作仍需要现有工作线程边界。**一个应用/账号一个 peer 是身份与隔离规则,不是一个 Agent 对应一个 Tokio task 或 OS 线程。** +## 11. 测试与尚待实现的部分 -## 11. 本次验证与读代码练习 +[Broker 测试](../crates/app-peers/tests/broker.rs)提供可执行协议示例:`a_persons_message_runs_while_the_system_agents_input_runs`、`a_lane_stop_leaves_the_other_lane_running`、`a_kernel_without_shared_history_is_refused_for_the_conversation`、`removing_an_account_purges_its_recorded_peer_and_drops_the_record`。[Shell relay 场景测试](../crates/shell/src/host_tools/scenario_tests.rs)覆盖调用方、工具与审批边界;修改对话或执行路径时从这些测试开始。 -已运行并通过:使用现有 clone hub 的 setup,以及 `python3 tools/setup.py --check --cargo`;`python3 tools/native_apps.py --check`;`python3 -m unittest discover -s rom/tests -p test_no_local_paths.py`;五个文档 worktree 的相对文件链接和 `git diff --check`。另外,`cargo test --locked -p octosense-kernel -p octosense-app-peers --features octosense-app-peers/octos-core,octosense-app-peers/ws` 的单元与脚本化连接测试也通过。真实内核测试未提供所需二进制环境变量,会提前返回,**不算真实内核集成验证**。 +在仓库根目录运行单元测试与脚本化连接器测试: + +```sh +cargo test --locked -p octosense-kernel -p octosense-app-peers \ + --features octosense-app-peers/octos-core,octosense-app-peers/ws +``` -[broker 测试](../crates/app-peers/tests/broker.rs)可作为逐步练习:阅读 `a_persons_message_runs_while_the_system_agents_input_runs`、`a_lane_stop_leaves_the_other_lane_running`、`a_kernel_without_shared_history_is_refused_for_the_conversation` 和 `removing_an_account_purges_its_recorded_peer_and_drops_the_record`。它们不需要付费模型即可展示协议行为。[relay 场景测试](../crates/shell/src/host_tools/scenario_tests.rs)展示调用者和审批边界;本次仅阅读,未运行。 +可选真实内核测试在缺少二进制环境变量时提前返回;将结果当作集成证据前,阅读 [app-peers 测试说明](../crates/app-peers/README.md)。可见 UI、真实提供方对话和设备行为需要分别运行。 -桌面 GUI、真实提供方回合、Android/OpenHarmony/iOS 构建、ROM 构建及刷机均**未验证**。`AGENT.md` 提示词加载、应用包自动技能/触发器、任意脚本实现的 Agent 工具及通用应用到系统 Agent RPC 仍有实现缺口。一个架构示例是否能实际执行,要同时检查声明、授权和执行器。 +尚待实现:应用包 `AGENT.md` 提示词加载、自动 triggers/skills、脚本实现的 Agent 工具分发,以及通用应用到系统 Agent 对话 RPC。围绕这些路径设计流程前,沿声明追到实际执行器。 diff --git a/docs/architecture.md b/docs/architecture.md index 75e8a13f..08e5267c 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -2,7 +2,7 @@ English | [简体中文](architecture.zh-CN.md) -How OctoSense fits together: which processes run on each platform, where the agents live, how the pieces talk, how tools are granted and approved, where data and secrets are kept, and where the trust boundaries are. The current code-reading companion is the [junior-Rust walkthrough](architecture-walkthrough.md), checked against OctoSense `c19da8d` and its octos `ae230ce0` pin on 2026-10-01. This reference retains dated design/review history; the corrections below reflect that snapshot. +How OctoSense fits together: processes, agents, tools, approvals, storage and trust boundaries. Follow the [code walkthrough](architecture-walkthrough.md) for calls and ownership. Dependency versions come from [Cargo.toml](../Cargo.toml) and [native-runtime.lock.json](../native-runtime.lock.json); the dated design notes below record earlier decisions. Every statement carries its status: @@ -77,7 +77,7 @@ flowchart LR | process apps | | octos kernel (child; in process on OHOS)| | Terminal, ... | | system agent session | +-----------------+ | app peers: one per (app, account) | - | tools run as short child processes | + | turns and tool dispatch | Talk to Octos clients ---------> +-----------------------------------------+ (external token, allowlist, opt-in) ``` @@ -160,7 +160,7 @@ flowchart TB ## 2. Agents -**One kernel per shell; agents are sessions, not processes.** Inside the one kernel, agent turns run as Tokio tasks, while peers and sessions are durable state. A peer can have multiple context sessions and a turn can create several tasks; there is no one-agent/one-task mapping. See the [thread and task table](architecture-walkthrough.md#10-map-the-architecture-to-rust-execution). Tools such as file edits run in the kernel; octos's command tools run as short child processes in the session's workspace (OctoSense denies them to the system agent, [section 4](#4-tools-and-grants)). +**One kernel per shell; agents are sessions, not processes.** Inside the one kernel, agent turns run as Tokio tasks, while peers and sessions are durable state. A peer can have multiple context sessions and a turn can create several tasks; there is no one-agent/one-task mapping. See the [thread and task table](architecture-walkthrough.md#10-map-the-architecture-to-rust-execution). Tools such as file edits run in the kernel; octos's command turns and tool dispatch in the session's workspace (OctoSense denies them to the system agent, [section 4](#4-tools-and-grants)). | Agent | What it is | Status | | --- | --- | --- | @@ -172,7 +172,7 @@ Each app peer has, separately from every other: - a **workspace**: the folder the peer's session is bound to. A peer created since the octos 665209e5 pin gets its account folder (`apps//accounts//`, ADR 0004 §11) as `peer/prepare`'s `cwd` (`host_tools::agent_workspace`), recorded beside its host token so a resume names the same folder; a peer created before keeps the kernel-provisioned one, since octos refuses to resume a peer under another workspace (see [the disagreements](#where-the-code-and-the-adrs-disagree)); - a **memory namespace** `app//acct-` (`app_namespace()` in `crates/app-peers/src/broker.rs`); a kernel that does not return it is refused; - its own **transcript** and **model** lane (the host sets the model with `peer/prepare` / `peer/model/set`); -- its own **tool list**: exactly the kernel tools its manifest grants (`generic_tools`, never octos's `shell`) plus the tools the shell registers (octos [#2567](https://github.com/octos-org/octos/pull/2567), UPCR-2026-035): after every `peer/prepare` and reconnect the broker registers, on the connection that drives the peer's turns, the app's declared tools and the other apps' shareable tools granted to it, each marked with its owning app (`crates/shell/src/host_tools/`), with `generic_tools` set to exactly the kernel tools the app's manifest declares and the person granted (a native app's `native-apps.json` `agent.generic_tools`, a script app's plain names in its manifest's `agent.tools`; an app that names none keeps none). The Terminal declares `terminal.run`, `terminal.read_screen` and `terminal.read_scrollback`; News declares `news.list` and `news.read` (`apps/news/bundle/tools.json`, on its host service). A peer that cannot register runs no turn; +- its own **tool list**: exactly the kernel tools its manifest grants (`generic_tools`, never octos's `shell`) plus the tools the shell registers (octos [#2567](https://github.com/octos-org/octos/pull/2567), UPCR-2026-035): after every `peer/prepare` and reconnect the broker registers, on the connection that drives the peer's turns, the app's declared tools and the other apps' shareable tools granted to it, each marked with its owning app (`crates/shell/src/host_tools/`), with `generic_tools` set to exactly the kernel tools the app's manifest declares and the person granted (a native app's `native-apps.json` `agent.generic_tools`, a script app's plain names in its manifest's `agent.tools`; an app that names none keeps none). The Terminal declares `terminal.run`, `terminal.read_screen` and `terminal.read_scrollback`; News declares `news.list`, `news.read` and `news.notify` (`apps/news/bundle/tools.json`, on its host service). A peer that cannot register runs no turn; - **request contexts** (`peer/context/open`): one per client instance (a Rinx mini app), each with its own transcript, folder `contexts//` inside the peer's workspace and child memory namespace. Such a client's context cannot read the files beside it directly; it reads its account's data through the shell's host read tools `files.list`, `files.read` and `files.search` (ADR 0004 §11, `crates/shell/src/host_tools/files.rs`), which never show another context's folder. Besides those per-client contexts (`OctosAppService::open_context`: Rinx's mini apps, a process app's `octos.session.open` with a `client`), each app conversation is one more request context: the person's own conversation with an app agent, from the app's UI or its cards, runs in the person's lane, a context opened with `share_history` that runs in parallel with the peer's own session (the system agent's lane) and shows each lane the other's recent turns (ADR 0004 §6, decided 2026-09-29; below). That conversation context is opened with octos's `read_parent` where the manifest says the agent works in the account folder (`storage.agent_workspace: "account"`, octos#2647): it reads the account folder read-only, never another context's folder, and writes only its own. Who gets a peer today (`crates/ai-host/src/lib.rs`, `Policy::shipped()`; `crates/app-peers/src/hosted.rs`, `effective_services` = declared ∩ supported ∩ policy): @@ -270,7 +270,7 @@ Where an agent's tools come from: | Source | Example | Runs | Status | | --- | --- | --- | --- | -| The app's own tools (`tools.json`: name `.`, schemas, `risk`, `confirm: host` or `app`, `shareable`) | `news.list`, `terminal.read_screen`, `mail.send`, `rinx.message.send` | the app's host service, module or process, called by the shell | On main (`crates/shell/src/host_tools/`): declared from `native-apps.json` `agent.tools` (native) or the admitted bundle's `tools.json` (script, `host_tools/script_apps.rs`, with App Hub's loader), authorized by (owning app, tool) and caller, arguments and results checked against the declared schemas, budgeted, stamped with account, context and client, and routed to a process app's peer link, an in-process module's executor (`OctosAppService::set_tool_executor`), a script app's host service (`HostServiceExecutor`) or the Terminal's AI bus service. News offers `news.list` and `news.read`; the Terminal `terminal.run` and its read tools | +| The app's own tools (`tools.json`: name `.`, schemas, `risk`, `confirm: host` or `app`, `shareable`) | `news.list`, `terminal.read_screen`, `mail.notify`, `calendar.add_event` | the app's host service, module or process, called by the shell | On main (`crates/shell/src/host_tools/`): declared from `native-apps.json` `agent.tools` (native) or the admitted bundle's `tools.json` (script, `host_tools/script_apps.rs`, with App Hub's loader), authorized by (owning app, tool) and caller, arguments and results checked against the declared schemas, budgeted, stamped with account, context and client, and routed to a process app's peer link, an in-process module's executor (`OctosAppService::set_tool_executor`), a script app's host service (`HostServiceExecutor`) or the Terminal's AI bus service. News offers `news.list`, `news.read` and `news.notify`; the Terminal `terminal.run` and its read tools | | The system toolbox, by capability (`research`, `crawl`, `model`) | `toolbox.search`, `toolbox.web_read`, `toolbox.deep_crawl`, `workflow.run` | host | In progress ([#108](https://github.com/OctoSense-org/OctoSense/pull/108)); `model` not registered yet | | octos's generic tools | file reads fenced to the workspace, memory, `web_search`, `deep_search` | octos | On main per app: each peer is registered with exactly its granted `generic_tools` (Rinx: its workspace files, `ask_user_question`, memory, the web); an app granted none keeps none; octos's `shell` is never among them (the generator, the catalog and the script loader drop it), and the `_main` profile's `tool_policy` denies it too | | Other apps' shareable tools, routed by the shell | Calendar's agent calling `mail.send` | the owning app, via the shell | On main (`relay::Catalog`): granted by (owning app, tool), from `native-apps.json` `agent.grants` (native) or the dotted names in a script app's `agent.tools` (at install), registered marked with the owner, checked on every call. None of today's apps is granted one | @@ -392,7 +392,7 @@ One host-owned layout for every app, declared by its manifest (`storage` block) ## 8. Worked example: emailing a meeting invite -"Ask the system agent to email a meeting invite." This is ADR 0004's Calendar and Mail example. **Almost all of it is planned**: there is no Calendar app on `main`, Mail declares no `tools.json` or `octos.*` yet, and the kernel side (`peer/input`, host-registered tools) is octos#2567. The status column says which pieces exist. +This ADR 0004 example combines an implemented Calendar action with a **planned Mail send tool**. Calendar ships `calendar.add_event`; Mail currently exposes only `mail.notify` to its agent. Completing this workflow requires a declared/shareable `mail.send`, admission and caller grants, and its executor. The broker, relay and approval mechanisms below already exist. ```mermaid sequenceDiagram @@ -406,7 +406,7 @@ sequenceDiagram S->>C: peer_send_input (brief) Note over S,SH: octos delivers peer/input to the host SH->>C: turn/start (app's tools, memory, context) - C->>SH: peer/tool/call calendar.create_event + C->>SH: peer/tool/call calendar.add_event SH-->>C: result C->>SH: peer/tool/call mail.send x3 (caller: Calendar) SH->>SH: grant check: Calendar granted mail.send? @@ -427,13 +427,13 @@ sequenceDiagram | Step | What happens | Status | | --- | --- | --- | -| 1 | The person asks the system agent, in the system conversation `_main:api:octosense#system`. | On main: the shell's system chat ([#132](https://github.com/OctoSense-org/OctoSense/pull/132)), or a paired Talk to Octos client (the desktop's AI pane is Makepad's `aichat` on the bus, not the system agent) | -| 2 | The system agent plans. Ambiguity is asked, not guessed ("two Edwards?"); for a bounded read it may call a granted tool directly. Work that needs Calendar's judgement goes to Calendar's agent with `peer_send_input`. | `peer_send_input` on main; direct cross-app grants planned (step 6) | +| 1 | The person asks the system agent, in the system conversation `_main:api:octosense#system`. | On main: the shell's system chat ([#132](https://github.com/OctoSense-org/OctoSense/pull/132)), or a paired Talk to Octos client (the system assistant pane is separate from an app's Makepad `aichat` bus interface) | +| 2 | The system agent plans. Ambiguity is asked, not guessed ("two Edwards?"); for a bounded read it may call a granted tool directly. Work that needs Calendar's judgement goes to Calendar's agent with `peer_send_input`. | `peer_send_input` and relay grants implemented; this example's Mail tool/grant still planned | | 3 | octos delivers the input to the shell as `peer/input`; the shell starts the turn on Calendar's peer with `turn/start`, so it has Calendar's tools, memory and account context. If Calendar's peer has no host connection, the system agent is told the app is not connected. | On main ([octos#2567](https://github.com/octos-org/octos/pull/2567) in the pin; the broker starts the turn) | -| 4 | Calendar's agent calls `calendar.create_event` (its own tool) and Mail's shareable `mail.send` once per invitee. Each call reaches the shell as `peer/tool/call`; the shell stamps the caller (Calendar's agent), account and context. | Relay on main (`host_tools`); Calendar and Mail's tools planned | -| 5 | The shell checks that Calendar's manifest was granted `mail.send` (at install for a script app); no second, agent-level consent. | Check on main (`relay::Catalog`); install-time grants planned (step 6) | +| 4 | Calendar's agent calls `calendar.add_event` (its own tool) and Mail's shareable `mail.send` once per invitee. Each call reaches the shell as `peer/tool/call`; the shell stamps the caller (Calendar's agent), account and context. | Calendar action and relay implemented; `mail.send` planned | +| 5 | The shell checks that Calendar's manifest was granted `mail.send` (at install for a script app); no second, agent-level consent. | Relay and App Hub admission checks implemented; this specific grant/tool is absent | | 6 | `mail.send` is outward and `confirm: host`, so the approval router takes it: developer mode off; not `confirm: app`; not `auto_approvable: false`; a standing rule on (Mail, `mail.send`) such as "send to my contacts" approves it (notified and audited; the contacts condition holds only once the person turned on "Use my contacts in approval rules"), else one batched shell sheet shows each invitation: owning app Mail, tool `mail.send`, calling app Calendar, the exact arguments. | Router, rules, sheets and audit on main ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)); fed by kernel `host_tool` approvals through the relay | -| 7 | On approval the shell hands each call to Mail's host service, which sends with the account the person signed in to on Mail's host sheet (the password never reaches the agent), and returns the result to the kernel as `peer/tool/result`. | Mail's host service on main (`apps/mail/host-service`); its tools as agent tools planned | +| 7 | On approval the shell hands each call to Mail's host service, which sends with the account the person signed in to on Mail's host sheet (the password never reaches the agent), and returns the result to the kernel as `peer/tool/result`. | Mail host service implemented; its agent has `mail.notify`, while `mail.send` remains planned | | 8 | Calendar's turn ends and octos writes `peers//result.md` and `turns.txt`; the system agent reads it with `peer_gather`. A failed invitation is named, and one with an unknown outcome is never retried without the person. | Blackboard on main (octos) | | 9 | The system agent announces "Booked Tue 3 pm; invitations sent to 3". Calendar's and Mail's own UIs show the change because their data changed. | Planned | diff --git a/docs/architecture.zh-CN.md b/docs/architecture.zh-CN.md index 9906980d..1d9b021b 100644 --- a/docs/architecture.zh-CN.md +++ b/docs/architecture.zh-CN.md @@ -2,7 +2,7 @@ [English](architecture.md) | 简体中文 -OctoSense 的各部分如何组合在一起:每个平台上运行哪些进程、Agent 在哪里、各部分如何通信、工具如何授权和审批、数据与机密存放在哪里,以及信任边界在哪里。最新[初学者代码导读](architecture-walkthrough.zh-CN.md)于 2026-10-01 核对 OctoSense `c19da8d` 及其 octos `ae230ce0` 锁定版本。本文保留标注日期的设计/审查历史;下列修订反映该源码快照。 +OctoSense 的进程、Agent、工具、审批、存储与信任边界。具体调用和所有权见[代码导读](architecture-walkthrough.zh-CN.md)。依赖版本以 [Cargo.toml](../Cargo.toml) 和 [native-runtime.lock.json](../native-runtime.lock.json) 为准;下方带日期的设计记录保留早期决策。 每条陈述都标明状态: @@ -77,7 +77,7 @@ flowchart LR | 进程应用 | | octos 内核(子进程;OHOS 上在进程内) | | Terminal 等 | | 系统 Agent 会话 | +-----------------+ | 应用 peer:每个(应用,账号)一个 | - | 工具以短时子进程运行 | + | 回合执行与工具分发 | Talk to Octos 客户端 ----> +-----------------------------------------+ (外部 token、允许列表、需手动开启) ``` @@ -160,7 +160,7 @@ flowchart TB ## 2. Agent -**每个 Shell 一个内核;Agent 是会话,不是进程。** 在这一个内核中,每个 Agent 都是一个以 tokio 任务运行的 octos 会话。文件编辑之类的工具在内核中运行;octos 的命令类工具在会话的工作区中以短时子进程运行(OctoSense 不让系统 Agent 使用它们,见[第 4 节](#4-工具与授权))。 +**每个 Shell 一个内核;Agent 是会话,不是进程。** 在这一个内核中,Agent 回合由 Tokio 任务执行,peer 与 session 是持久状态。一个 peer 可包含多个 context session,一个回合也可创建多个任务。实际线程与任务对应关系见[导读](architecture-walkthrough.zh-CN.md#10-映射到-rust-的实际执行模型)。文件编辑之类的工具在内核中运行;octos 的命令类工具在会话的工作区中以短时子进程运行(OctoSense 不让系统 Agent 使用它们,见[第 4 节](#4-工具与授权))。 | Agent | 是什么 | 状态 | | --- | --- | --- | @@ -391,7 +391,7 @@ flowchart TB ## 8. 完整示例:用邮件发送会议邀请 -“让系统 Agent 发一封会议邀请邮件。”这是 ADR 0004 中的 Calendar 与 Mail 示例。**其中几乎全部都在规划中**:`main` 上没有 Calendar 应用,Mail 还没有声明 `tools.json` 或 `octos.*`,内核一侧(`peer/input`、宿主注册的工具)是 octos#2567。状态一栏说明哪些部分已经存在。 +此 ADR 0004 示例组合了已实现的 Calendar 操作与**规划中的 Mail 发信工具**。Calendar 已提供 `calendar.add_event`;Mail 当前只向 Agent 暴露 `mail.notify`。完成流程还需要声明可共享的 `mail.send`、准入与调用方授权,以及执行器。下方的 broker、relay 与审批机制已经实现。 ```mermaid sequenceDiagram @@ -405,7 +405,7 @@ sequenceDiagram S->>C: peer_send_input(任务说明) Note over S,SH: octos 把 peer/input 送到宿主 SH->>C: turn/start(应用的工具、记忆、上下文) - C->>SH: peer/tool/call calendar.create_event + C->>SH: peer/tool/call calendar.add_event SH-->>C: 结果 C->>SH: peer/tool/call mail.send x3(调用方:Calendar) SH->>SH: 授权检查:Calendar 是否获授权 mail.send? @@ -426,13 +426,13 @@ sequenceDiagram | 步骤 | 发生什么 | 状态 | | --- | --- | --- | -| 1 | 用户在系统对话 `_main:api:octosense#system` 中向系统 Agent 提出请求。 | 目前只能从已配对的 Talk to Octos 客户端访问;Shell 还没有自己的系统 Agent 对话界面(桌面端的 AI 面板是总线上的 Makepad `aichat`,不是系统 Agent) | -| 2 | 系统 Agent 做计划。有歧义就提问,不去猜(“两个 Edward?”);有限的读取可以直接调用获授权的工具。需要 Calendar 自己判断的工作用 `peer_send_input` 交给 Calendar 的 Agent。 | `peer_send_input` 已在 main;直接的跨应用授权规划中(步骤 6) | +| 1 | 用户在系统对话 `_main:api:octosense#system` 中向系统 Agent 提出请求。 | 目前只能从已配对的 Talk to Octos 客户端访问;Shell 还没有自己的系统 Agent 对话界面(系统助手面板与应用的 Makepad `aichat` 总线接口分别实现) | +| 2 | 系统 Agent 做计划。有歧义就提问,不去猜(“两个 Edward?”);有限的读取可以直接调用获授权的工具。需要 Calendar 自己判断的工作用 `peer_send_input` 交给 Calendar 的 Agent。 | `peer_send_input` 与 relay 授权已实现;此示例的 Mail 工具/授权仍在规划中 | | 3 | octos 把输入以 `peer/input` 送到 Shell;Shell 在 Calendar 的 peer 上用 `turn/start` 启动回合,使其带有 Calendar 的工具、记忆和账号上下文。如果 Calendar 的 peer 没有宿主连接,系统 Agent 会被告知该应用未连接。 | 已在 main(锁定版本含 [octos#2567](https://github.com/octos-org/octos/pull/2567);由 broker 启动回合) | -| 4 | Calendar 的 Agent 调用 `calendar.create_event`(自己的工具),并为每位受邀者调用一次 Mail 可共享的 `mail.send`。每次调用都以 `peer/tool/call` 到达 Shell;Shell 盖上调用方(Calendar 的 Agent)、账号和上下文。 | 中继已在 main(`host_tools`);Calendar 和 Mail 的工具规划中 | -| 5 | Shell 检查 Calendar 的清单是否获授权 `mail.send`(脚本应用在安装时授权);不需要第二道 Agent 级别的同意。 | 检查已在 main(`relay::Catalog`);安装时授权规划中(步骤 6) | +| 4 | Calendar 的 Agent 调用 `calendar.add_event`(自己的工具),并为每位受邀者调用一次 Mail 可共享的 `mail.send`。每次调用都以 `peer/tool/call` 到达 Shell;Shell 盖上调用方(Calendar 的 Agent)、账号和上下文。 | Calendar 操作与中继已实现;`mail.send` 规划中 | +| 5 | Shell 检查 Calendar 的清单是否获授权 `mail.send`(脚本应用在安装时授权);不需要第二道 Agent 级别的同意。 | Relay 与 App Hub 准入检查已实现;此特定授权/工具尚不存在 | | 6 | `mail.send` 是对外的 `confirm: host` 工具,由审批路由处理:开发者模式未开启;不是 `confirm: app`;不是 `auto_approvable: false`;如果有针对(Mail,`mail.send`)的常设规则(例如“发给我的联系人”),就由规则批准(通知并审计;只有用户打开了“在审批规则中使用我的联系人”,联系人条件才会成立),否则一个合并的 Shell 面板列出每封邀请:所属应用 Mail、工具 `mail.send`、调用方应用 Calendar 以及确切参数。 | 路由、规则、面板和审计已在 main([#120](https://github.com/OctoSense-org/OctoSense/pull/120));经中继由内核的 `host_tool` 审批提交请求 | -| 7 | 批准后,Shell 把每次调用交给 Mail 的宿主服务,它用用户在 Mail 宿主面板上登录的账号发送(密码永远不会到达 Agent),并把结果以 `peer/tool/result` 返回内核。 | Mail 的宿主服务已在 main(`apps/mail/host-service`);把它的工具作为 Agent 工具还在规划中 | +| 7 | 批准后,Shell 把每次调用交给 Mail 的宿主服务,它用用户在 Mail 宿主面板上登录的账号发送(密码永远不会到达 Agent),并把结果以 `peer/tool/result` 返回内核。 | Mail 宿主服务已实现;Agent 已有 `mail.notify`,`mail.send` 仍在规划中 | | 8 | Calendar 的回合结束,octos 写入 `peers//result.md` 和 `turns.txt`;系统 Agent 用 `peer_gather` 读取。失败的邀请会被点名,结果未知的邀请未经用户同意绝不重试。 | 黑板已在 main(octos) | | 9 | 系统 Agent 宣布“已预订周二下午 3 点;已向 3 人发送邀请”。Calendar 和 Mail 自己的界面会显示变化,因为它们的数据变了。 | 规划中 | diff --git a/phone/AGENTS.md b/phone/AGENTS.md index d6bd684b..b9d5ca84 100644 --- a/phone/AGENTS.md +++ b/phone/AGENTS.md @@ -1,24 +1,23 @@ # Working on Home -Follow the [repository rules](../AGENTS.md) and the -[product source walkthrough](../desktop/docs/code-walkthrough.md). +Follow the [repository rules](../AGENTS.md) and use the +[product walkthrough](../desktop/docs/code-walkthrough.md) to trace events. -- Run Home Cargo commands from `phone/`: `.cargo/config.toml` selects its - system bundles. `mobile-only` chooses phone presentation on desktop; - `mobile-apps` links extra native modules. They are not synonyms. -- Keep shared shell changes in `../crates/shell/`. Home's `App` wraps the - shared `App` and adds Settings; preserve the before/after event ordering in - `src/main.rs` when changing platform integration. -- Settings is privileged through its compiled trusted module identity, not a - script-provided name. Preserve request attribution, freshness, correlation - and observed-state checks at Rust/Java boundaries. -- The octos system agent, System Bridge and ROM `AgentPlatformService` are - distinct components. Binder permissions are not LLM tool grants. Standalone - Home does not gain the ROM's platform signature or permissions. -- APK building, installation and ROM flashing are separate operations. Follow - `../rom/docs/home-build.md` for the supported Home/Bridge build. Use only an - assigned device and a separate test package; no device result may be inferred - from desktop preview or compilation. -- Apply the root's phone checks to code changes. For doc-only changes, check - paths, features and links, keep README languages paired, and label unrun - build/device instructions unverified. +- Run Home Cargo commands from `phone/`; its `.cargo/config.toml` selects the + phone bundles. Use `mobile-only` for phone presentation on desktop and + `mobile-apps` to link Reference/Sheets for testing. +- Put shared shell changes in `../crates/shell/`. Keep Home's Settings, + platform clients and packaging here. Preserve the before/after shell event + order in `src/main.rs` when changing `App::handle_event`. +- Keep Settings authority tied to the trusted compiled module. Preserve + request attribution, freshness and correlation checks across the Rust/Java + boundary. Update the relevant `settings_*_host.rs` tests with behavior changes. +- Verify platform changes against both the Java client and its Android + contract. Handle accepted commands separately from observed platform state; + show unavailable capabilities as unavailable. +- Use `../rom/docs/home-build.md` for Home/Bridge packaging. Validate on an + assigned device with a separate test package, following the root's device + rules. Record device evidence separately from desktop preview results. +- Run the root's phone/shared-shell checks after code changes. Update both + README languages when build flags, platform behavior or supported entry + points change. diff --git a/phone/README.md b/phone/README.md index 091e5ac8..2a3d5b54 100644 --- a/phone/README.md +++ b/phone/README.md @@ -2,7 +2,7 @@ English | [简体中文](README.zh-CN.md) -**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, real app data and Android platform boundaries; it marks unrun recipes explicitly. +**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, app data and Android platform boundaries. > **Where this fits.** On a phone, OctoSense-hosted native modules and script apps run in the Home process (no desktop-style hosted process apps); ordinary Android apps still run in their own Android processes. The octos kernel is the APK's `liboctos.so` as a child process on Android, an in-process task on OpenHarmony, and absent on iOS. Apps still reach their agents only through the shell. Diagrams of the processes, an app agent's two lanes and a tool call with its approval: [How it fits together](../README.md#how-it-fits-together); the details: [docs/architecture.md](../docs/architecture.md) and [ADR 0004](../docs/adr/0004-native-apps-hosting-and-peers.md). @@ -241,8 +241,8 @@ by the default `app-hub` feature and on every mobile build. The **Preview catalog** switch shows the built-in apps while the live catalog is empty. See the crate's -[README](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/46d67e51b62827a1224b1aacddc2a7b9e69185fc/crates/app-hub-app/README.md) -at the pinned revision and the [native design evidence](docs/design/app-hub/README.md). +[README](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/crates/app-hub-app/README.md) +(read the revision selected by the root `Cargo.toml`) and the [native design evidence](docs/design/app-hub/README.md). App authors start with [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow). diff --git a/phone/README.zh-CN.md b/phone/README.zh-CN.md index 3a70f3c5..71c25141 100644 --- a/phone/README.zh-CN.md +++ b/phone/README.zh-CN.md @@ -2,7 +2,7 @@ [English](README.md) | 简体中文 -**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、真实数据和 Android 平台边界,并明确标注未运行的配方。 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、应用数据和 Android 平台边界。 > **在整个系统中的位置。**在手机上,OctoSense 托管的原生模块和脚本应用在 Home 进程内运行(不使用桌面式进程托管);普通 Android 应用仍在各自的 Android 进程中运行。octos 内核在 Android 上是 APK 中作为子进程运行的 `liboctos.so`,在 OpenHarmony 上是进程内的任务,在 iOS 上没有。应用仍然只能通过 Shell 使用自己的 Agent。进程、应用 Agent 的两条通道以及一次带审批的工具调用的图示:[整体如何运作](../README.zh-CN.md#整体如何运作);详细说明:[docs/architecture.zh-CN.md](../docs/architecture.zh-CN.md) 和 [ADR 0004(英文)](../docs/adr/0004-native-apps-hosting-and-peers.md)。 @@ -138,7 +138,7 @@ AI 提供商(`os.ai-providers`)通过 `llm` 宿主服务([`apps/ai-provide App Hub(`apphub`)用于浏览已签名的 OctoSense 应用目录、搜索、查看应用详情、安装经过验证的应用包,并维护已安装应用的应用库。已安装的应用在隔离的 Card 实例(`card`)中打开,并在启动器和最近任务中单独显示。两者都来自 App Hub 的共享 Shell crate `octosense-app-hub-app`(OctoSense-App-Hub 中的 `crates/app-hub-app`),由默认的 `app-hub` feature 链接,且包含在所有移动端构建中。**预览目录**开关会在线上目录为空时显示内置应用。 -参见该 crate 在固定版本下的 [README(英文)](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/46d67e51b62827a1224b1aacddc2a7b9e69185fc/crates/app-hub-app/README.md) 以及 [原生设计依据(英文)](docs/design/app-hub/README.md)。应用开发者可从 [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow) 开始。 +参见该 crate 的 [README(英文)](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/main/crates/app-hub-app/README.md) (阅读根 `Cargo.toml` 选定的版本)以及 [原生设计依据(英文)](docs/design/app-hub/README.md)。应用开发者可从 [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow) 开始。 ## 在桌面电脑上运行 diff --git a/phone/android/README.md b/phone/android/README.md index 026b6819..87606b73 100644 --- a/phone/android/README.md +++ b/phone/android/README.md @@ -57,8 +57,7 @@ Outputs: Build the Makepad packager in the pinned checkout `.sources/makepad` (prepared by `python3 tools/setup.py` from the repository root) after its source changes, then invoke its standalone binary from `phone/`. This builds without installing. -**Unverified in this documentation review**; this low-level command is not the -Home/Bridge pair build or kernel receipt pipeline. Use +**Unverified recipe.** For the Home/Bridge pair and kernel receipt pipeline, use [the supported build](../README.md#build-and-run) for those artifacts: ```sh diff --git a/phone/android/README.zh-CN.md b/phone/android/README.zh-CN.md index 1de90539..9bff0ecf 100644 --- a/phone/android/README.zh-CN.md +++ b/phone/android/README.zh-CN.md @@ -31,7 +31,7 @@ export GRADLE_USER_HOME="$OCTOSENSE_TOOLS/gradle-cache" - `system-bridge/build/reports/lint-results-prototype.html`。 - `quickstep/build/outputs/apk/prototype/quickstep-prototype.apk`。 -Makepad 打包器的源码变更后,在固定版本的检出目录 `.sources/makepad`(在仓库根目录运行 `python3 tools/setup.py` 准备)中构建它,然后在 `phone/` 下调用其独立二进制文件。以下命令只构建、不安装,**本次文档审查未验证**。这是底层打包命令,不是 Home/Bridge 配对构建与内核回执流水线;完整产物请使用 [Home README 的构建流程](../README.zh-CN.md): +Makepad 打包器的源码变更后,在固定版本的检出目录 `.sources/makepad`(在仓库根目录运行 `python3 tools/setup.py` 准备)中构建它,然后在 `phone/` 下调用其独立二进制文件。以下命令只构建、不安装,**未验证配方**。Home/Bridge 配对构建与内核回执流水线请使用 [Home README 的构建流程](../README.zh-CN.md): ```sh # From .sources/makepad: diff --git a/rom/AGENTS.md b/rom/AGENTS.md index 1f88ec99..c725e684 100644 --- a/rom/AGENTS.md +++ b/rom/AGENTS.md @@ -1,19 +1,23 @@ # Working on the ROM -The [repository rules](../AGENTS.md) apply. Read the -[product source walkthrough](../desktop/docs/code-walkthrough.md) and -[Home build contract](docs/home-build.md) before changing packaging docs. +Follow the [repository rules](../AGENTS.md), +[Home build contract](docs/home-build.md) and +[product walkthrough](../desktop/docs/code-walkthrough.md). -- `vendor/octosense/` is the Android product/platform layer. Home and the - System Bridge are built from `../phone/`; do not revive a `home/` source copy. -- The Java/Binder privileged agent is not the octos LLM system agent. Document - package/signature gates separately from assistant consent/tool policy. -- Keep build, artifact receipt verification, staging, signing, installation, - flashing and release steps explicit. A successful build is not evidence that - the image boots or that platform functions work. -- Do not install, flash or publish as part of a documentation review. Device - work requires the user's assigned device and authorized scope. Keep signing - material and machine paths outside this repository. -- Run the applicable Python/script checks from the root instructions for code - changes. For docs, check relative links and source-backed command arguments, - pair README languages and mark unexecuted commands/device work unverified. +- Put Android product, permission, sepolicy and privileged-service changes in + `vendor/octosense/`. Build Home and System Bridge from `../phone/`. +- Preserve the package/signature checks in `AgentPlatformService` and the + AIDL contract used by Home. Update the corresponding Java clients and + platform validation fixtures when a contract changes. +- Keep build receipts, staging and signing inputs consistent across + `build-home.py`, `stage-home.py` and the product makefiles. Keep signing + material and machine configuration outside the repository. +- Run `python3 -m unittest discover -s tests` from `rom/` for build/staging + changes and syntax-check changed shell scripts with `bash -n`. Validate + AIDL changes with `python3 scripts/generate-agent-aidl.py --check --sdk "$ANDROID_HOME"` + with the configured Android SDK, as described in the README. +- Follow the root's assigned-device rules for installation/flashing. Use the + README's device checks to verify boot, platform functions and OTA behavior + before release; retain the resulting validation record. +- Update both README languages when the product layout, artifact contract or + build/flash sequence changes. diff --git a/rom/README.md b/rom/README.md index 722b1ddf..83f36fcc 100644 --- a/rom/README.md +++ b/rom/README.md @@ -2,7 +2,7 @@ English | [简体中文](README.zh-CN.md) -**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, real app data and Android platform boundaries; it marks unrun recipes explicitly. +**New to the code?** Read the [desktop, Home, ROM and system-app walkthrough](../desktop/docs/code-walkthrough.md), then the [agent and Tokio walkthrough](../docs/architecture-walkthrough.md). The first follows launch, native hosting, script bundles, app data and Android platform boundaries. The OctoSense ROM is LineageOS 22.2 (Android 15) for the OnePlus 6 (`enchilada`) with the OctoSense Home app preinstalled beside a privileged diff --git a/rom/README.zh-CN.md b/rom/README.zh-CN.md index 6092b41c..97d84a89 100644 --- a/rom/README.zh-CN.md +++ b/rom/README.zh-CN.md @@ -2,7 +2,7 @@ [English](README.md) | 简体中文 -**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、真实数据和 Android 平台边界,并明确标注未运行的配方。 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、应用数据和 Android 平台边界。 OctoSense ROM 是面向 OnePlus 6(一加 6,`enchilada`)的 LineageOS 22.2(Android 15),预装 OctoSense Home 应用以及具有系统权限的 agent、Quickstep 和 SystemUI,让 Agent 进入系统层。本目录只包含镜像本身:产品层、补丁、构建/签名/刷写/更新镜像的脚本,以及网页安装器。它原是 OctoSense-ROM 仓库(已停用,并入本仓库;其中的 `home/` 现为 [`../phone/`](../phone/README.zh-CN.md));见 [ADR 0001(英文)](../docs/adr/0001-one-octosense-repository.md)。 From b8491bcc1dd8b61c481e4e4aea007f25d34f8d39 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:59:38 -0700 Subject: [PATCH 3/6] docs: keep companion walkthrough links stable after merge --- docs/architecture-walkthrough.md | 2 +- docs/architecture-walkthrough.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md index 8145e089..35bf1cf6 100644 --- a/docs/architecture-walkthrough.md +++ b/docs/architecture-walkthrough.md @@ -19,7 +19,7 @@ This walkthrough follows a message from an app window through the shell, agent k | Tool / host service | A tool is an operation offered to the model. A host service is Rust code called by an app or tool executor. Exposing one API does not automatically expose the other. | | `AGENTS.md` / `AGENT.md` | Repository contributor instructions / an app-bundle agent-instructions artifact. The bundle artifact is admitted by App Hub, but is not yet loaded into the shell peer's prompt. | -The companion code tours cover [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/docs/junior-architecture-walkthrough/docs/CODE-WALKTHROUGH.md), [App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/docs/junior-architecture-walkthrough/docs/CODE-WALKTHROUGH.md), [Octoscript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad/blob/docs/junior-architecture-walkthrough/docs/architecture-walkthrough.md) and [octos](https://github.com/octos-org/octos/blob/docs/junior-architecture-walkthrough/docs/octosense-integration-walkthrough.md). These links select the published documentation branches; runtime versions remain controlled by each consumer's dependency pins. +The companion code tours cover [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/71163c03d55edd3e6371947e1d6eab8f982bf088/docs/CODE-WALKTHROUGH.md), [App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/f560e9b1e751d9ab7d4ba7f74204ee37056d27dd/docs/CODE-WALKTHROUGH.md), [Octoscript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad/blob/5c05e1a20fc0b92a6a211d3cd512eaf256040706/docs/architecture-walkthrough.md) and [octos](https://github.com/octos-org/octos/blob/0cfa32e838f582ff00a2661ba067723322f3c16a/docs/octosense-integration-walkthrough.md). These links select published documentation revisions; runtime versions remain controlled by each consumer's dependency pins. ## 2. Start at the executable, then follow the app host diff --git a/docs/architecture-walkthrough.zh-CN.md b/docs/architecture-walkthrough.zh-CN.md index c4064245..5a4307d2 100644 --- a/docs/architecture-walkthrough.zh-CN.md +++ b/docs/architecture-walkthrough.zh-CN.md @@ -19,7 +19,7 @@ | Tool / host service | Tool 是模型可选择的操作;host service 是应用或执行器调用的 Rust 服务。分别检查它们的授权与入口。 | | `AGENTS.md` / `AGENT.md` | 前者指导仓库贡献者;后者是应用包的 Agent 指令文件。App Hub 会准入后者,但 Shell 尚未把它加载进 peer 提示词。 | -相关仓库的导读:[Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/docs/junior-architecture-walkthrough/docs/CODE-WALKTHROUGH.md)、[App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/docs/junior-architecture-walkthrough/docs/CODE-WALKTHROUGH.md)、[Octoscript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad/blob/docs/junior-architecture-walkthrough/docs/architecture-walkthrough.md)、[octos](https://github.com/octos-org/octos/blob/docs/junior-architecture-walkthrough/docs/octosense-integration-walkthrough.md)。这些链接指向已发布的文档分支;运行时版本仍由使用方的依赖锁定文件控制。 +相关仓库的导读:[Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/71163c03d55edd3e6371947e1d6eab8f982bf088/docs/CODE-WALKTHROUGH.md)、[App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/f560e9b1e751d9ab7d4ba7f74204ee37056d27dd/docs/CODE-WALKTHROUGH.md)、[Octoscript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad/blob/5c05e1a20fc0b92a6a211d3cd512eaf256040706/docs/architecture-walkthrough.md)、[octos](https://github.com/octos-org/octos/blob/0cfa32e838f582ff00a2661ba067723322f3c16a/docs/octosense-integration-walkthrough.md)。这些链接指向已发布的文档版本;运行时版本仍由使用方的依赖锁定文件控制。 ## 2. 从可执行入口读到应用宿主 From 1ca3a521a89f51fd08a631b308a8f279bec0d0fc Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:08:33 -0700 Subject: [PATCH 4/6] docs: distinguish shipped Glance notices from chat-capable cards --- README.md | 13 +++++-------- README.zh-CN.md | 13 +++++-------- apps/README.md | 5 ++--- apps/README.zh-CN.md | 7 +++---- desktop/docs/code-walkthrough.md | 4 +++- desktop/docs/code-walkthrough.zh-CN.md | 2 +- docs/architecture-walkthrough.md | 2 ++ docs/architecture-walkthrough.zh-CN.md | 2 ++ docs/images/agents-card-flow.png | Bin 465761 -> 381344 bytes 9 files changed, 23 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index e2767520..3362f4df 100644 --- a/README.md +++ b/README.md @@ -123,18 +123,15 @@ sequenceDiagram R->>R: grant, consent, schema, budget R->>M: run on Mail's host service M->>G: glance.publish as os.mail: notice.card, notify - G-->>P: notification (a desktop toast, the phone's shade) + G-->>P: desktop: a toast and the glance panel; phone: a shade notification M-->>R: {card_id} R-->>A: peer/tool/result A-->>S: the turn's result on the blackboard (peer_gather) - P->>G: opens the card, types in its chat - G->>A: a turn in the person's lane (sys.chat) - A-->>G: the reply, drawn as AI-written ``` -- The notice tools fill `crates/shell/resources/glance/notice.card` through `glance_notice.rs`; Mail and News delegate to it from their host-service callbacks. Calendar ships its own event and agenda templates in `apps/calendar/host-service/resources/`. These tools accept content and publish a fixed L0 template as the app. +- The notice tools fill `crates/shell/resources/glance/notice.card` through `glance_notice.rs`; Mail and News delegate to it from their host-service callbacks. Calendar ships its own event and agenda templates in `apps/calendar/host-service/resources/`. These tools accept content and publish a fixed L0 template as the app. The shipped notice, event and agenda templates declare no `sys.chat`; use “Ask ” to discuss them with the app agent. - `mail.notify` and `calendar.add_event` are `act` tools and run without a sheet; octos asks for approval only for destructive and outward tools, which go to the shell's approval router ([below](#a-tool-call-with-an-approval)). ### One app agent, two lanes @@ -181,8 +178,8 @@ The person is not limited to the system agent: they can talk to any app's own ag | Surface | Where it is | How it opens | | --- | --- | --- | | **"Ask "** (`crates/shell/src/app_chat/`) | A shell panel for every app with an agent, whether or not the app draws a chat of its own: the system chat's pane drawn as the app's conversation (`app_panel: true`). On a desktop it stands right of the system chat, so the two lanes show side by side. | The bar's "Ask " button (shown while the focused window's app has an agent), Shift+F8, or the menu row "Ask this app's agent". With an app without an agent focused, the shell says "No app agent here". On the phone the pane is drawn as a full-screen sheet, but no touch control opens it on `main` yet. | -| **A card's in-card chat** (`sys.chat`, `crates/shell/src/glance_chat.rs`) | A glance card the app published | The person types in the card's chat. Only the publishing app's own agent answers, and its reply is marked AI-written ([below](#cards-and-questions)). | -| **The app's own UI** | A native module's `open_conversation`, a script app's `octos.session.open`, a process app's peer link | Inside the app. Rinx draws its own assistant UI; none of the system apps (News, Mail, Calendar) draws a chat, so for them the panel and their cards are the way in. | +| **A card's in-card chat** (`sys.chat`, `crates/shell/src/glance_chat.rs`) | A glance card the app published | The person types in the card's chat. A card declaring `sys.chat` routes to its publishing app's agent, whose reply is marked AI-written ([below](#cards-and-questions)). The shipped agent notice and Calendar cards contain no chat; the Mail demo card uses canned replies. | +| **The app's own UI** | A native module's `open_conversation`, a script app's `octos.session.open`, a process app's peer link | Inside the app. Rinx draws its own assistant UI; none of the system apps draws a chat, so the “Ask ” panel is their current conversation entry. | How the "Ask " panel behaves: @@ -239,7 +236,7 @@ sequenceDiagram ### Cards and questions -- **Glance cards** (`crates/shell/src/glance.rs`): an app with the `glance` capability publishes with `glance.publish` (`glance.withdraw`, `glance.list`), as itself: the shell takes the publisher from the caller, never from the arguments. A card is an L0 `source` filled from `data` (presentation only, checked with Octoscript's L0 checker) or a Splash `script`. Limits: 6 publishes a minute and 4 cards per app, 32 kept, 6 shown by priority, then recency. A card published with `notify` also posts a notification: on a desktop the toast opens that card in its own card window (`glance_sheet.rs`), and the glance panel (`glance_panel.rs`; the bar's bell, F9) opens on every new card; on a phone the shade's notification opens the glance page. +- **Glance cards** (`crates/shell/src/glance.rs`): an app with the `glance` capability publishes with `glance.publish` (`glance.withdraw`, `glance.list`), as itself: the shell takes the publisher from the caller, never from the arguments. A card is an L0 `source` filled from `data` (presentation only, checked with Octoscript's L0 checker) or a Splash `script`. Limits: 6 publishes a minute and 4 cards per app, 32 kept, 6 shown by priority, then recency. A card published with `notify` also posts a notification: on a desktop the toast opens that card in its own card window (`glance_sheet.rs`), and a new card opens the glance panel (`glance_panel.rs`; the bar's bell, F9) unless a card window is already open. Toasts stack beside the open panel. Cards have dismiss buttons (`glance::dismiss`), and the panel has a close button. On a phone the shade's notification opens the glance page. - **Interactive cards** ([#153](https://github.com/OctoSense-org/OctoSense/pull/153)): an app's glance cards run under the app's own policy, as the app's UI does in the Card runner. What the person does on a card is the app's own action, through the app's capability gate and host services, not an agent tool call, so it needs no extra shell approval. - **In-card chat** ([#263](https://github.com/OctoSense-org/OctoSense/pull/263)): an L0 card may declare `sys.chat(app, thread, fields)` and draw `ChatEntry` rows, and show text the model wrote (`class: model-copy`), marked AI-written and never acted on. The transcript is the host's ([`crates/l0-chat`](crates/l0-chat/README.md), `crates/shell/src/glance_chat.rs`): only the publishing app's own agent, only what the person typed is written as theirs, and the agent answers in the person's lane. Threads are kept in the app's account folder (`apps//accounts//chat/.json`). - **Questions** (octos's `ask_user_question`) are routed by the turn's trigger: a turn from the person's lane (or the app) asks in the app's conversation, a turn from the system agent's lane asks in the system chat. Only the person answers, on a shell surface. diff --git a/README.zh-CN.md b/README.zh-CN.md index 453ed650..6645feb1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -122,18 +122,15 @@ sequenceDiagram R->>R: grant, consent, schema, budget R->>M: run on Mail's host service M->>G: glance.publish as os.mail: notice.card, notify - G-->>P: notification (a desktop toast, the phone's shade) + G-->>P: desktop: a toast and the glance panel; phone: a shade notification M-->>R: {card_id} R-->>A: peer/tool/result A-->>S: the turn's result on the blackboard (peer_gather) - P->>G: opens the card, types in its chat - G->>A: a turn in the person's lane (sys.chat) - A-->>G: the reply, drawn as AI-written ``` -- 通知工具经 `glance_notice.rs` 填充 `crates/shell/resources/glance/notice.card`;Mail 和 News 的宿主服务回调委派到这里。Calendar 的事件与议程模板位于 `apps/calendar/host-service/resources/`。这些工具接收内容,以应用身份发布固定 L0 模板。 +- 通知工具经 `glance_notice.rs` 填充 `crates/shell/resources/glance/notice.card`;Mail 和 News 的宿主服务回调委派到这里。Calendar 的事件与议程模板位于 `apps/calendar/host-service/resources/`。这些工具接收内容,以应用身份发布固定 L0 模板。随产品提供的通知、事件与议程模板均未声明 `sys.chat`;通过 “Ask ” 与应用 Agent 讨论这些卡片。 - `mail.notify` 和 `calendar.add_event` 是 `act` 工具,运行时不弹面板;octos 只对破坏性和对外的工具请求审批,这些审批交给 Shell 的审批路由([见下文](#一次带审批的工具调用))。 ### 一个应用 Agent,两条通道 @@ -180,8 +177,8 @@ flowchart TB | 入口 | 位置 | 如何打开 | | --- | --- | --- | | **“Ask ”**(`crates/shell/src/app_chat/`) | Shell 为每个拥有 Agent 的应用提供的面板,不论应用自己是否绘制对话界面:它就是系统对话的窗格,以应用对话的形式绘制(`app_panel: true`)。在桌面端,它位于系统对话的右侧,两条通道并排显示。 | 顶栏的 “Ask ” 按钮(当前聚焦窗口的应用拥有 Agent 时显示)、Shift+F8,或菜单项 “Ask this app's agent”。如果聚焦的应用没有 Agent,Shell 会提示 “No app agent here”。在手机上,这个窗格绘制为全屏面板,但 `main` 上还没有可以打开它的触控入口。 | -| **卡片的卡内对话**(`sys.chat`,`crates/shell/src/glance_chat.rs`) | 应用发布的一张 glance 卡片 | 用户在卡片的对话里输入。只有发布卡片的应用自己的 Agent 会回答,它的回复标为 AI 撰写([见下文](#卡片与提问))。 | -| **应用自己的界面** | 原生模块的 `open_conversation`、脚本应用的 `octos.session.open`、进程应用的 peer link | 在应用内。Rinx 绘制自己的助手界面;系统应用(新闻、邮件、日历)都不绘制对话界面,所以对它们来说,入口就是这个面板和它们的卡片。 | +| **卡片的卡内对话**(`sys.chat`,`crates/shell/src/glance_chat.rs`) | 应用发布的一张 glance 卡片 | 用户在卡片的对话里输入。声明了 `sys.chat` 的卡片将消息交给发布应用的 Agent,回复标为 AI 撰写([见下文](#卡片与提问))。随产品提供的 Agent 通知卡片与 Calendar 卡片没有聊天;Mail 演示卡片使用预设回复。 | +| **应用自己的界面** | 原生模块的 `open_conversation`、脚本应用的 `octos.session.open`、进程应用的 peer link | 在应用内。Rinx 绘制自己的助手界面;系统应用都不绘制对话界面,目前通过 “Ask ” 面板与它们的 Agent 对话。 | “Ask ” 面板的行为: @@ -238,7 +235,7 @@ sequenceDiagram ### 卡片与提问 -- **Glance 卡片**(`crates/shell/src/glance.rs`):拥有 `glance` 权限的应用用 `glance.publish`(以及 `glance.withdraw`、`glance.list`)以自己的身份发布卡片:Shell 从调用方取得发布者,从不读取参数里的发布者。卡片要么是由 `data` 填充的 L0 `source`(只有呈现,由 Octoscript 的 L0 检查器检查),要么是 Splash `script`。限制:每个应用每分钟发布 6 次、最多保留 4 张卡片,总共保留 32 张,按优先级再按时间显示 6 张。以 `notify` 发布的卡片还会发出一条通知:桌面端点击 toast 会在单独的卡片窗口中打开这张卡片(`glance_sheet.rs`),每来一张新卡片 glance 面板(`glance_panel.rs`;顶栏的铃铛、F9)都会打开;手机上点通知栏里的通知会打开 glance 页面。 +- **Glance 卡片**(`crates/shell/src/glance.rs`):获得 `glance` 权限的应用用 `glance.publish` 发布,以 `glance.withdraw` 撤回、`glance.list` 查询。Shell 从调用方确定发布身份。卡片可使用由 `data` 填充并检查的 L0 `source`,或 Splash `script`。每应用每分钟最多发布 6 次、保留 4 张,整个存储保留 32 张,按优先级和时间展示 6 张。桌面有新卡片时自动打开 glance 面板(顶栏铃铛、F9),但已有卡片窗口打开时例外。`notify` 还显示 toast,点击会打开该卡片窗口;面板打开时 toast 排在其旁边。卡片有移除按钮(`glance::dismiss`),面板有关闭按钮。手机的 `notify` 通知出现在通知栏,点击打开 glance 页面。 - **交互式卡片**([#153](https://github.com/OctoSense-org/OctoSense/pull/153)):应用的 glance 卡片在应用自己的策略下运行,与应用界面在 Card runner 中一样。用户在卡片上的操作是应用自己的操作,经过应用的能力闸门和宿主服务,而不是 Agent 的工具调用,因此不需要额外的 Shell 审批。 - **卡内对话**([#263](https://github.com/OctoSense-org/OctoSense/pull/263)):L0 卡片可以声明 `sys.chat(app, thread, fields)` 并绘制 `ChatEntry` 行,也可以显示模型写的文字(`class: model-copy`),这些文字标为 AI 撰写,且从不被当作操作执行。对话记录归宿主所有([`crates/l0-chat`](crates/l0-chat/README.md)、`crates/shell/src/glance_chat.rs`):只能与发布卡片的应用自己的 Agent 对话,只有用户亲手输入的内容才记为用户的话,Agent 在用户的通道里回答。对话按线程保存在应用的账号文件夹中(`apps//accounts//chat/.json`)。 - **提问**(octos 的 `ask_user_question`)按这一轮的触发方路由:来自用户通道(或应用)的一轮在应用的对话中提问,来自系统 Agent 通道的一轮在系统对话中提问。只有用户能回答,而且只能在 Shell 的界面上回答。 diff --git a/apps/README.md b/apps/README.md index 8ba252d1..e6ad1ca2 100644 --- a/apps/README.md +++ b/apps/README.md @@ -402,7 +402,7 @@ See the [data-access walkthrough](../desktop/docs/code-walkthrough.md#4-follow-a - **Talking to it yourself.** The person can chat with the app's agent directly, not only through the system agent: in the "Ask " panel, which the shell draws for every app with an agent (none of these apps - draws a chat of its own), or in a card's in-card chat. Those turns run + draws a chat of its own). The shipped notice and Calendar cards have no chat field. A custom card declaring `sys.chat` can use the same human lane. Those turns run in the person's lane, beside the system agent's, with the app's tools. The panel's Stop stops only the person's own turn. On the phone no touch control opens the panel yet. See the root @@ -426,8 +426,7 @@ See the [data-access walkthrough](../desktop/docs/code-walkthrough.md#4-follow-a is published with `notify` through the shell's `glance` service as the app (the app needs the `glance` capability). The model only supplies the text; it never writes card code. - A card can hold an in-card chat with the app's own agent (`sys.chat`, - [`../crates/l0-chat`](../crates/l0-chat/README.md)). + These notice, event and agenda templates contain no `sys.chat`. A custom card can declare in-card chat with its app's agent ([`../crates/l0-chat`](../crates/l0-chat/README.md)); the Mail demo card uses canned replies. - **Trying it** on the desktop: open the assistant (F8) and ask the system agent to have an app's agent (Mail, Calendar, News, Photos, Maps or YouTube) put a card on the glance screen; diff --git a/apps/README.zh-CN.md b/apps/README.zh-CN.md index 461e189c..af88318a 100644 --- a/apps/README.zh-CN.md +++ b/apps/README.zh-CN.md @@ -349,8 +349,8 @@ Agent 开放。Peer 的工作目录也不会挂载 Mail 的宿主数据库或凭 然后把 peer 的 slug 交给系统 Agent,让请求在同一轮里继续。只有系统 Agent、用户或卡片的卡内对话发起请求时才会 开始一轮:还没有触发器或定时任务(ADR 0002 M3,计划中)。 - **直接与它对话。** 用户可以直接与应用的 Agent 对话,而不只是通过系统 Agent:在 Shell - 为每个拥有 Agent 的应用提供的 “Ask ” 面板里(这些应用都不绘制自己的对话界面), - 或在卡片的卡内对话里。这些回合在用户的通道里运行,与系统 Agent 的通道并列,带着应用的 + 为每个拥有 Agent 的应用提供的 “Ask ” 面板里(这些应用都不绘制自己的对话界面)。 + 随产品提供的通知与 Calendar 卡片没有聊天字段;声明了 `sys.chat` 的自定义卡片可使用同一用户通道。这些回合在用户的通道里运行,与系统 Agent 的通道并列,带着应用的 工具。面板的“停止”只停止用户自己的回合。手机上还没有打开这个面板的触控入口。详见根目录的 [README](../README.zh-CN.md#直接与应用的-agent-对话)。 - **它的工具在应用的宿主服务上运行**,以应用的身份运行,在此之前 Shell 的中转已检查授权、 @@ -365,8 +365,7 @@ Agent 开放。Peer 的工作目录也不会挂载 Mail 的宿主数据库或凭 `card_id` 会替换该应用之前的通知。邮件和新闻的服务把 `notify` 交给 Shell;照片、地图、YouTube 和相机没有自己的服务,由 Shell 的通知服务应答。`calendar.notify` 和 `calendar.agenda` 填充日历 自己的日程卡片和议程卡片。每张卡片都以应用的身份、带 `notify` 通过 Shell 的 `glance` 服务发布 - (应用需要 `glance` 权限)。模型只提供文字,从不编写卡片代码。卡片里可以有与应用自己的 Agent 的卡内对话 - (`sys.chat`,[`../crates/l0-chat`](../crates/l0-chat/README.md))。 + (应用需要 `glance` 权限)。模型只提供文字,从不编写卡片代码。这些通知、事件和议程模板没有 `sys.chat`。自定义卡片可声明与应用 Agent 的卡内对话([`../crates/l0-chat`](../crates/l0-chat/README.md));Mail 演示卡片使用预设回复。 - **试一试**(桌面端):打开助手(F8),请系统 Agent 让某个应用的 Agent(邮件、日历、新闻、照片、 地图或 YouTube)在 glance 屏幕上放一张卡片;在弹出的面板上允许该 Agent。邮件需要一个已登录的账户(下文的演示邮箱即可)。 邮件更完整的操作卡片([计划(英文)](mail/docs/2026-10-01-email-action-card-plan.md))目前只是 diff --git a/desktop/docs/code-walkthrough.md b/desktop/docs/code-walkthrough.md index 43b69204..c8e32893 100644 --- a/desktop/docs/code-walkthrough.md +++ b/desktop/docs/code-walkthrough.md @@ -213,7 +213,9 @@ On desktop, focus an agent-enabled app and open **Ask <app>** from the bar Shift+F8 or the menu. F8 opens the system agent. `agents.list` reports app agents; `agents.ask` waits for first-use consent and peer preparation, then returns the peer slug. The system agent sends the task with `peer_send_input` and gathers its -answer with `peer_gather`. A card's `sys.chat` can address its own app agent. +answer with `peer_gather`. A card declaring `sys.chat` can address its own app +agent. Shipped notice and Calendar templates have no chat, so use “Ask ” +for those agents; the Mail demo card answers with canned text. Phone touch navigation has no Ask-app panel-opening control yet. Follow [`app_chat/`](../../crates/shell/src/app_chat/mod.rs), diff --git a/desktop/docs/code-walkthrough.zh-CN.md b/desktop/docs/code-walkthrough.zh-CN.md index 62f1f727..4e7e6377 100644 --- a/desktop/docs/code-walkthrough.zh-CN.md +++ b/desktop/docs/code-walkthrough.zh-CN.md @@ -183,7 +183,7 @@ relay 也必须授权。准入还检查 `HostLimits.offered_tools`:默认提 桌面上聚焦拥有 Agent 的应用,从栏按钮、Shift+F8 或菜单打开 **Ask <app>**。 F8 打开系统 Agent。`agents.list` 报告应用 Agent;`agents.ask` 等待首次同意和 peer 准备完成,再返回 peer slug。系统 Agent 用 `peer_send_input` 发送任务,用 `peer_gather` -获取答案。卡片的 `sys.chat` 也可以访问其应用 Agent。手机触控导航尚无打开 Ask-app 面板的控件。 +获取答案。声明了 `sys.chat` 的卡片也可以访问其应用 Agent。随产品提供的通知与 Calendar 模板没有聊天,应通过 “Ask ” 访问其 Agent;Mail 演示卡片返回预设文本。手机触控导航尚无打开 Ask-app 面板的控件。 继续阅读 [`app_chat/`](../../crates/shell/src/app_chat/mod.rs)、 [`system_chat/`](../../crates/shell/src/system_chat/mod.rs)、 diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md index 35bf1cf6..d6de70f5 100644 --- a/docs/architecture-walkthrough.md +++ b/docs/architecture-walkthrough.md @@ -125,6 +125,8 @@ The broker's `driver_of` and `take_over` handle multiple native instances sharin | A script app's own chat | Exact granted `octos.session.open`, `octos.session.history`, `octos.turn.start`, `octos.turn.interrupt` calls through `host.request`. The shipped system-app agents are shell-driven without their scripts declaring these calls. | | A published card's chat | `sys.chat` → [l0-chat](../crates/l0-chat/src/lib.rs) and [glance_chat.rs](../crates/shell/src/glance_chat.rs). Publisher checks bind it to the card's owning app. | +The shipped `.notify`, `calendar.notify` and `calendar.agenda` templates contain no `sys.chat`; their agents are reached through “Ask ”. The `OCTOSENSE_GLANCE_DEMO=mail` demonstration card has chat but uses canned replies (`glance_chat::HostResponder`). The card-chat route above applies to a card that declares `sys.chat`. + Phone touch navigation does not yet expose an equivalent control to open the Ask-app panel; app-owned chat and published-card chat are separate surfaces. The Ask-app panel's Stop interrupts the human lane; “Stop the system agent's task” targets the other lane. The lower-level conversation `ContextOp::Interrupt` is broader and can interrupt both: do not assume all Stop surfaces call the same method. Hiding the Ask panel keeps its context/subscription; changing app or revoking access closes it. The shell stamps a composer action as `TurnTrigger::Person`. A script can supply `trigger`/`from` with `octos.turn.start`, but its `trigger: "person"` becomes `AppSaysPerson`: a transcript label is not proof of a trusted human gesture and cannot unlock human-initiated approval rules. diff --git a/docs/architecture-walkthrough.zh-CN.md b/docs/architecture-walkthrough.zh-CN.md index 5a4307d2..aac00e12 100644 --- a/docs/architecture-walkthrough.zh-CN.md +++ b/docs/architecture-walkthrough.zh-CN.md @@ -125,6 +125,8 @@ sequenceDiagram | 脚本应用自己的聊天 | 经 `host.request` 调用确切获授权的 `octos.session.open`、`octos.session.history`、`octos.turn.start`、`octos.turn.interrupt`。随产品提供的系统应用 Agent 由 Shell 驱动,其脚本无需声明这些调用。 | | 已发布卡片中的聊天 | `sys.chat` 经 [l0-chat](../crates/l0-chat/src/lib.rs) 与 [glance_chat.rs](../crates/shell/src/glance_chat.rs) 到达发布者的 Agent;宿主核对卡片归属。 | +随产品提供的 `.notify`、`calendar.notify` 与 `calendar.agenda` 模板不含 `sys.chat`,通过 “Ask ” 与其 Agent 对话。`OCTOSENSE_GLANCE_DEMO=mail` 演示卡片带有聊天,但由 `glance_chat::HostResponder` 返回预设答案。上表的卡片聊天路线适用于声明了 `sys.chat` 的卡片。 + 手机触控导航尚无打开 Ask-app 面板的对应控件;应用自己的聊天与卡片聊天是另外的入口。Ask-app 面板的 Stop 中断用户通道,“Stop the system agent's task” 中断系统通道。底层 `ContextOp::Interrupt` 范围更大,可以中断两条通道。隐藏面板保留 context 和订阅;切换应用或撤销访问会关闭它。 Shell 将聊天输入动作标为 `TurnTrigger::Person`。脚本调用 `octos.turn.start` 可传 `trigger` / `from`,但 `trigger: "person"` 被记录为 `AppSaysPerson`;脚本标签不能作为可信用户动作来匹配审批规则。 diff --git a/docs/images/agents-card-flow.png b/docs/images/agents-card-flow.png index 83b96f0c260ce0b45c2b047e2679432f033e7aba..2525c2f5f1666c260acb6f015bebd51e93fcc603 100644 GIT binary patch delta 377112 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 z zzgcn(R(EcibR4P`r4pUd*T2t#G`-0Q_yDU&YcmH$eS~Mcuu7D!g;UP|Qi@ajp&muv zA*_&k&DZ#BW(#b~!#Vj||8{yYT$IyS&HKG-O5_Y28$7quq+YoA&_o$PP00{5<)Cwdq!8=E$TXRXLj z#1r}-c0x29xUagh}8K-ItQxS}13#iCfv!Z6?Dtd88Uu!C)qF?3} zon&lVl>^V=xQ|!3s4X+YP~AJx7L9$0?)Kg*Gh|Lg_?aW6c<6kh&7vgU>Cp{-XXm%y z+i!Z6957>r@f(n8g?bqA{#`<5wGKFI+VBDvn zZFs&oc1b&!?{mK5?GS+TIi^xuj2_viRWsS!?PkQCgSuDKJr$C)VDy6O>hiMLF2Yx`{jIotyJA5B&Y|r^(9xwRA~zI z`3MS#P#_!2gm7o<6vq1=4`^Lv?2eQRucT}>pwdDTeB(k+0#-o#SP(PI_6?58@p``!=_#1Y?l zKZ<52p5Cb+Sc1xffrs|1&zWyhBZ$x@xBhI8GAy9!>nc2<=vbd&bq%t}Milz|Gfe)LvJVpC z6ojB_+y>0#kM!yO^d}x5f`$)>UE?)B)S;;^5YwDz^UNzkuGtt(v_V1<7>`poIT z7r2_^!!H_ahFnw$zP0wIKG00Hd;msTpH9aa*S60z|+uWI@UojirIv#g%(Zj28+C)2%seKdF% z!cutznKCMfT{}&Ww+iekTq`8pot=}mdGS@cuwbeldTN-TXsiqQj@c?$`7b^uF= z!i7crJ;8LKu-MqcJ73K@_F-ZK?VGAFkDer^Y}kJvQtOx(ID%#O&Y&4jM#s^{bw9@W zaelu21z1S}aJ`UMpQS0q^Gl|2{f{2)6GDOm28!WFx(5q>m$~FJ6ptS|N9_Q9TopW_ z?8R{3fE+w~39t*l(D#ra0kGawSBuQ|!mH3>4x+f!9kT1r zgx^Xfz@z<8*+Pol)GXm zTR>`>Y~>n?{eq*t1Q#u4DWL`=2NBIPOJ@<(@CzqU`|c-r=kkv1+E`e5OjFn?=o)so z&@<&J7rtN8K(mJ7WbNh__8u9VFMwpk`Y+ux!rmNC;g@n*l;lY-P!Fz=Nz;n$u_({; zoR&r2m+Aa&F4Z5eOuN>h*}V*)sHPn4PG2!@*(1j$7fub~DGKV25K|^fTan)BCU5{@ z{GptMO2w~teVf4jUa^%l9iJUxlmv5Enh>kGw}QnT_Fsh_LX+70k#+zA^J%`Ws8GQb z{%~)=CdGEdwTY~3{Q}BF50?OksXbpmL5IT)4aYdZuQ-|vR2eO~<(HxrT)J|;fPn=B zBV;%R7eJc2sHJ@A&fXF4VXQv-$uB$d?md~7k(GY2L?yo|T*F^O1K!~Y)A+Z=((X!; z%ATy3or4R0ZT-!;Y&H@O+%GDCdOosId z;26V?ckJvjfuHaQF`;BK>9UHCb23cvq_+Wt4j5;BA51i@|5fQuq~>!*V6fKzdD-Pz zE*tKeEx6s#oZ~Csq@ak0gsE1UbJ~VD{oOk=Ojda=R3s~)kQSYWaZNU1uo=GEw=2FSzGZUPzIOb`B8 za$GCsxH-|`TV%1=RK!jLK8-Xs!_5~1RA zN+%=xiX2ZF`sk;q2UMGWL*|1i0d9rq)6{P`u zpT989z@&M>zEfJoGKW->80d-bu}cke3AQfH(3_ktP(Ku|{KxN;WzaX|v-NqOAU-E+ z-}NR%$KdT}66!^>tNRX*-{k<@PE7SVGhzRYXYww!DV<4Y6-3MK@UWw`cQBQqwhpCI(dJ#b6Q5V`vS!G`( zQb0$Qr)K6OYoXibpSw>OdWeoEEx=!!1FWoQ-4|A6g{Nt<_Vg>zPgvfW(DqTGTj5mJ-BIR1xhgL?=s{e=z`I>L!GQWuFcZ0RH*%jqbPOk#U`qem6(1`y# z3=2{c{+;c+U~&}>7`@%jp*9Lec^4q0KL5QTWek%Gvv!kUGwxs_w_VE5<^_#J*PlT> z&;|WanYRety@-dkK{=+`t<2-?%&F(F%v2V-H7a*o?;^43(B)oO+iiZ8hQ0C@Y*K&z z?rxYz1;*|bU1;$xXpraEV|CXZ2K!t2MRW5B5Fx+tzhrD6x_#6-;J5NuOQZU%Cem+y z&UKB8K_v+5KZAB59@%U_UMy$G27uI0D!qG63uIaH#Lklxh2Tc@k$QP@eh&@Zc@pR(`{)NFzlW1;YOCd_#y z>L9taG0yC!bB3w7msy2p16>M%-P)!t5ptJ;P9bT=kR>D|vh zWwNbGOQw|cXiFUusEV8yYPK)pxj+4+D_cpAv;G3o6XT9^^p|zB;4*G1fR*Td8PYv# z)B64uzaPZH6&`>V^GT&I{O`ySFLMepfPfX(d?EPqqrNHLB<9P!O34?;*5A7?=e*t2 zrfa{LP#LvGWCilaFTd+Iv2NYkeG_(hoH%yK^Pp)Bm891uVh!INF(mc+uYGVgeO2^i z_oKMX#-fXvQ}eN46{}id^5pZeC9_<=R_d`u972P&9s?S|_U@KcGGWWQF5a)k*_!`g z)n_tYNzrIA|AtvN@m?GPI|1wA+4=T8Ab5xs$@L%)xEL1r% zXV>VMQzAp?_Ja$mT_La|V5LX4G5_&;h%1H<{v_Ls`MGv`Hu;qfS>6umyB*1wfe-om zTSS42$5DGo>XY6&i5t}1zB;G;R`AS!D<1PsBi_*RT6J)FFCsyXP%F-vS}N$N<-|dKAVMUekh zsg6-26@=L9<%x!qy}HXF4sd^*i*@NTYl}4B5$)XxoomsUp?N) zShC}rbWs{OK=bp1T5#kjNswU_#Th09h0`jUg?NU5WvJ?La-py#A$-6}`_EW3`R9Kj zELfN{_2c!^Ra$48>##`n-~ETQUQCQ&h?0Py8a{bd_W2f(j0^=%UDCuEed@wqWr#5z zM@D)YQR50(d&udYZ+wlkgu{3M)x+|ox&NjBE0^Ip z_z6dbq1(6tx(x6Ous5g+>K&GyNvT|OLQ@A|f^?Bz~b zE2|D$o+OYIV5tWQ{lEl{G2-?2ya9IH*cc+{zb5*A0oA|1)V4YfKb`V3g=Kn}n^_1= zgQl|vyo^7ju)|13;)xAyA~UE?zvVbAd81j)>4T6y0Neot0YA!)yykZ-Fm+W2akeyv zc>r{N-k|g>5?7;MU5z{`FUh@Sa_ z{}WUml~LC=ULR6G!kNHwnBNkeiRXQP@EHuWe%73Zp)?8ey~NQg5*Sjr@>Zv;YdW%{ z7}}xj23HN48x4h2C4D-JSEH&jJkTghj%MC2x<7WI>KDKSxSN&-s<55M{1)0trL4d} z&?>73uv0C}*`SbQSn|f)kb|Y7)yCX&#P4?-g&!*M$msVTPe~;a`ow=+MJS&W|8k2k zT8%5gMA&_LmFXYxiqE6(3~Qw~ zcIiww^&oGr?8IWYK;Q$%N2MBS2#`lKE<8dXSPtDFe5~{SkkM_wzp<294Dgu3 zyoIZePo}ZYF;YHe5>~`Gy(4y#i2Ya1^mXRXy+m6{|I|0908$OyANT<|5^Fv1EQ{Wt zKP4^{s0O=-rd-eT48$Hd=Z|_-ZAzg13*mC`*__RMGDQftwuXpjvRaW|p22AQg;A1~* zRaQN)#2oXa0E{tgR5*R^bgb3_om}{zbB>?fgxgroCwBL57x(uQUP95lRr^`)ZDpMV+6Ff1CS_b~I%DGGYJYeCGPj+!{6{T;Tl!uI`n6Jl8|Oq@*TG_)w_0;B)1tMqe#a()UZL z*W36`Lm|?O!coDod-@$o?}V#mt#oM$ca472f~A6gkX-ReADgg283Zkx9#ZK#4=p+V zO`fGSbj}EL3y@3vX63dS_sPgpO<*~iVoZl`LE%IGP*S|>#hMGlT$s+Ia#ZY|zt;~Q zr$*DlNLG0~Iyw4c1v-rOg$8RyX@g`?6C@e&PgCeORG9B1c`{RR220z>}#<@XIGeYY=@)Wv$0 zd-(2s+LoXH&PRL=Z(#+UJ&nQ}4bFxeOfNQ0)jD^r|VP2sctf2%C^e0IK%JPmd+W@WMDBbmX)A^<;YV6sjq zYFl8^=QnV`ni_PXmoB#W69?!D&FF$z4~wPf68Z z89~VAXrOh3sqgA?_Eb@Ds?lOM&?)Zu9p~Qx;PgBUXLc`ti5P8Y&t#N=bHuQb{4^)3 z{T3a%VdjCS96(9HF@NQH)({_~G~yx9bJrEbdVR?z=bPh1_~D8j&sRiLZjwpVB!lRbLIjoRwV9 zz~3#GONQ?KqSM*pN;>wL`{&g6h_>DioYObb=`s9;P^$STtACvT-d{zIx-yURX4Z@l zKd;~qmow{EsVE&BO?IsJStU$oVmr!idP>pu65p9=Y}{4e?`Aw4X$}d|ghb4C`~KLG zkVsF&g7NLc=UX`oY$@9*OAp7mEtc?PGGl`&aO(vEUz#qkNTKB!%U0*wBc{9v09DnS>|hZf^-4s=AA8 zhzq++sNb2&soVtQ(ixcUf~r>;bZOq!6&@=p!K4e$JNB*zFL-(!{!_hSH*8{JQBS;_ zw8OG^^pzmhU%d?TbHR(q-?J7}`(iBBjv2XGW^%LT^c)%%J_Z8tp>`iV-u;jc(O-*N z020BN-D>~a#ZVIssBUq>Xi7@vk!;&e&A1Os41LDRL-#EJWZpQ)Xv-uK!u*|Qj~W#Q zaE2f1-zs$(Xp7A}zlrK@!}AUoQ~+Xslo{~a+vv92?H>AkGDN88lVq32IlP1kSiKA< zuOGw(R@{lF;u3;1EXG29$+7{rSrrlsnxJ-B6o96dw3x$k6W43^J`f#P5V2n5QrTX5 z@KoEln!q$Kit@8mN{k2v;G#e-tT3wX+O=lyg`RsKS4-QXHO6(rm!B-MZU6>$;73>b zZ(}Jg#Rr&}txHoI6QcHWXz&unpF$W<|8sN}UQvBt8$UC2gObvSg7lYeP*f05x*HLc zE@`+Utw<={B_JY#bO?ilbc1wvx8%(H=6(NxyY5=|?z7L1=kp8|xyaIX;HU}Ad+EeZ zJSZ^4`DI-)|N8e`dj754hg?#IuQIo(R4$+4?G~)*gqA$E(t6ag+hKz-c23#*c$2;l z6B^|ego&y{X(l$`JeRY z9y2Grz0x+iwnmfTF$VwVt}99IeL?j2;nOEuLs1&3(m|3c(uHqcY$+8~%5z=$%UruN zve4!<*(u_9yqOR>E39yo%XXT+Qa1?e2o&x(LFfs|K)oM-TMo?--g zGEN!F9m1eVPp~6$Oc9#Zb?cAliOKEHEFBhle4lzh_&0K7e#ydqZeJY4#LVMws*BgW zYi&FN7Crymyf?!C&n4pN+>)|H823(wL(T`k{n4)`A{Bb4$*`8wuL)M_Im-V0%2V4_ z%!kf+GjF9@_zEBNCvx_XqE_#~+$k_hpv1IEQdiQ&aU)v3RyGzF%$F_}1^>3KN;H zhPhF(e&+G87h$c^sc03be=e(-^F9dmr^$?U|A5;2@s;83!-Nl7?NM2Ov0iQ-zC!Ws zIR!#3O)J&dTq%YsC~9Sv&dR_G8HbbNhe)eIf;LiJzePKKA9xI6YJP<#oHlni*}h*` z=iQsyVmH7GI}__JdEDabgJak>SFl1=ekNd4Fw|`pzx8%_FJM)`F?|Oy%pWNwl~a}+ znC$!bZ+iuC{Nu~FTQ6#YMIVqEsy-t!_dqU3V|eH@c7M6Qp~$!C3{52GIz~n5ty0so zKrF%U3E2Y4d02z9P!rgwdw>5-9DZTeBj7g!~>%vK7aSzDY8ZA3J5%H`ldi}O z&AKJ_j=ILrWRHkiuZ8+YuL3_;Z(V1!G4C_a>3;g#nh@~(x3d?v-}_E}ZoLB1@l>D4 zKXla5so`_=?Rz@(cN5#wc++MvwO+#o4EKLCx;+?Vdn3stjyacLFQ~5h^gWo1cj;M_ zL8WarrC6}PiZweWHX;ASk{tu2qoP+QeMUgv{6RY z^l;VA-U;(?E($s0D=?L$oA|E%rN6?PX2T#&Msc{Fvg8+$%Lk3;w`)04%+Tsu7zRh2a*}uZ`bTw}$5s@Z&KQo@;?ezsWtz(c#{FCT z&%4!hjjNoG?U-uY!x-NTMXvGuciuPBh;MZz#2-jx1WS5-{lqUf?yr`E=Up5)HuRteWd|H1KYk^*f(#g9$ zpn9s{c6ZNPU3H|M9FRiqCAnln4u^^Y3NH_6KaUL%rWK0ZoiA5YRNMN^t_B13Men|T z4nc*tEkVfD>>^c8(Ut-d3Z+~R_1Kh=N1EnOPB-PAQ<**1W=-a@pzrukl-9)9_zLpm zjk+0`$a2ei+cp>8+*w5!+SX4~IA@{{;5mJ%z5kptoEGGL*dPdVxHLbHmPf}rQLuh4 z`^PeUEgN}oU$!>leZ+eQiR)9FnUJ#O1#7LQ$gj*!-%?%d@o<-fEs?VwRC}Mb_I~mo zAm8OA+}h*|^iz^X$ifpBBVNRxbpy*vBoTVh z8Z(Y{R~|a1eP*KY;U|+ZmArw0)YW`2?NU|tJpYYwk7e2-pSV%9>gJEUaUPk^C0@A8 zN4NKGA_lArzBh6IWnIo(cuaEVr>YdFvttg|FMn{r6C(mWMK`^TnkQsFm1dpfLCU?^ zTwNF+Z}dJO?oaq8Ff6vgzO(b_z|!E|J~Ub9jl=j$-tUxNT>HTg7g6D7Ly&vc{YLB2@4lvZ z?+}bs!LEkMcWd=`uZ@42MD&OF`xzgz6O<28F0Bpr_o;+W@*jWXpdz-BaQXa1f|*S% zMt3pYBzPc`8u|L#V|Uy6{dWJa(&w5upr92tc%It>K{oR&datQ?Po6k0jW0PHwF%LO z({lpuM-pCZ8R=qgN;ye!l+-5fN$a#PgoGs&27ZZUkGs{9VQjwa#Fg9?$~PiCSDsH{ z$MH*L-YL&5|FG8Z_OqV*8A%uPEKlx4TG6MbxBbZwdZ%k|-G*zQy`r1{Tsh5rIj#PQ zofHRcWIyyM^<8Bs7PoQ-BeZgKAGKI$QSN15k^1Zf14mkSUK2Vga$3nND}Bkyrra2) z^SpsoRpFXHNx>gs9o!%TvWBFCgVy^U=^|dkn&JbRDqrjc1q2$3pC7IhR>bR~J*R?}@aX&2)FwExB8#=zEaknk0dFg~@+aE5Tl&SeSw)l01FH zTwdLRc%;R`#$n~hJ>;8fq58-P{pTjQEmg@u_2bmyMu?z=HofTmr`(|`eg?KT28Dm7Iu54( zIP-Ktc|P)wE;H6*Jg72=xG&}C+lDV0L_AIoyA<_1C0ud3orsh(-XMbtRf$%xuN3v* zm{Jk-!AQL_Lu77^6L+!@X1z;25t zFI0U`{)#U*YT|m{t!WyNZn6K4yUQOL3>V^ql3In&kCTRLc9GD_yU+URZTV=ao+=L2 z6)xb=u7=zFbCTZq^{EeY@;u{WI^J&d`nwawbB>TFtfyUhuZV~_?>o~oZtY?qCxMe7 z{Isz@O_6J6F~JK`cYa9}*=a*421(ZP8O{4KCk@FQVh(e74{nJ+*_|1?J$K2aeWhel z09jsBbqfcM{z@0nN88PWy}aI4Qk%l{6E*BK9!(`u?^eLyxwA+2$wH!I3Ll~3$ZIdx zmBh1#x%|iAeN@lI1|<={8Iel%dLuC>Ib_^W{Y=_NiFYyH^s@C;jhTcG-ztVnwt%GU z0Mlv0UY$INQ`GH8ovA1davoKve-EqFhF;1xhdM{pkwvsUL{98@SvsgOqUZL!{84CE zpEoY2vFvkKfk8GAyBg$M!(_4fGO=A~l>Ah>qwBoD?i7_tZD$$IbNXk>y~Ate6h(jB zM0+;=>>4xqiDI!kK4JlEOVO7n?jA$8abD(ce=f~;v~F2FAJ}jn3H%ok@(?+A0BJ}m z*GkZr*9T|%MQit@DDNfl#ErhN{+`eC#VR8yEii>HjHLuhty4#AYfGWvJp$MgrqO;bT{LvDLE9=hCh8JJt<@2xMhc!TP)Zwh;S z@VfiK7aHp2capjokF(!vt}PSGh~_(KaAN6MVDL27;SjL5w5 zZ1uLktkiX>b*m9NUt*K|PjaHJHN{87TYLa7d2rCe)=b4ab4P-=;}N@{OFfavyi@P< zc{EqVS0&!@hP_`u?<_>77&Ajcc5r5+u$@Kc?rMec5A{2OoBxF)0~~(T76)bu>dTY{ zQ&BxdXxOv7k+T1hTMbx6`mLHmH~KbyWVd2M`+3@ou5kovI!vbu6`_plWZo zvL<0;y+%ZaL&uSnhiW>1Qv|TFNrlW3^HAQQ5ofE??`^aFFJ4+f!7fCyb8o@|lCw+i zH0&tbm~fni{V0<4&R`;ldmtu#?=-TWcFF6(e^K)oA5mk5TGdpC&NHLCD2sXR`fWX# z#zu;uoXrZ;L&WK8@z*QRMO|W(BVCZ+uQx7~0`(B|*8Hu|C3^7YW_vsEeD6Og+}iQ+ zOH4k~1_mB$(u9FJVyx{Zy@SwEn2;Ag1e;ri+IWI+SSkfAO|V?TyBFn)8cgFWj->`d z8Kq5T72OYuvdkK)o3-gDDlv$?KTzwx)8dPi(zhSN{~O%Z%wB?wRTAe?Xw=&8KCKz; za}wZV`W?!|%b#Z*jHKYF_?yA?IjAJ*^r)^uuW>Vt7%et0PvIP7`n zZbm;=snOkzlBu;D%wnFNskB?|W!zFN3$mX5D0H`_(LnH^_g379%qIW+ntp8z$Jtub zLG$$n((Zb{v7-_?&LJ%(mcWWO7F@kv*VN~7-ylzSt@lI}QL$x=YgT98KJy1?iJJVo zv1M+J`k`}9Kfg9F|$`Dmi`g`5eij(T$eU26T~jQwE~U&J6`K$wO~PZiJ5Fk zRtbLG6g$`QCSSa+cAvL@wU0TiY(|}qdQ57DXUHo2j)fGK?gu5*WJ8~0^EyA>-HO=w z7js3k+f>lhp1j|=SX>nJ?M#@BD)l6^_Zc!P_l4eOLG{|Mp4?fiQsDJc1S>fvn$Z-! z6lit)~{ku(v+jMXIum2?@e>DYOmoc3w%*;8_zP4@N5pDbxnq{=Ap ze-(ZW~IG+P2TeqDXwg}xkIRlt~;9E)CVTE~ec-PLMz;j_99l?4dyPZrXV zCtlB*giZ%57l)fnd}3!@Z2U2pxqs;|uQQz`Nud_R%F0Su81b(_ec5+fW`lPO{y7Pj z${Y5^I4CqrDqyH;k_A)01YYL+TdCJ**`xXBj z*O+w(qp2{@+-~d4MA`hWrAKG|I}>FKb8SGd<3n`_eb|-_&42Y0ej0$8i8NjOr=bGE&)SOF_1A+o z#|v1B%jm&krtrj2cdmFdX;=oDYPdV|mupY~>3dh4CwUH^j3t^5(VG{jYfOE!#urHX zIvH~==z>eQsSFV3BpdyAzFJ%-{9XC(U-%d?%v}Fdzp>|+q+M(B&h&ii9DC!L9CS*3 zbo&JdQ~(epi@S-+MjojNr4!dYn#sq{O3*&>Jw{I&4OZ*!N6z8aUPbBL?Bw0lH{N(( zK2zA`ObtLkDbB9R8Fz2r_ftxZgF)lO1Xn(MEZrY@F^WzY{|X}D`l)X_d!pC!M%bza=8*E}^jZO(5(@5smLC8p1o)(F>3;MH4*w!Mlg;qwdxoJ})FCCy zVcw_hzs)izi4Pd)*5M^G@uB^LPizf@j6sMK=%y#FYU&{mor-mD9HKb&jw#=!_N-n_ zl*X0w!DShXAG+~8I|5=HxpyHpq*0~0|0VEfvgf-)s>wYk7M+s)ABEw10vN4rVT-7u zo8)%kON03J_{YCG%LJ=ebb)4PaGQ*3EidP^!<$lra+5&Pl(VUzpm8;YWbA_TFiMJ1 z53A@ykDd&|>FI}U8w@J`rQ)@)w_x|uT(Tk)e6cdi|#IzhmvYaMGx%|jlrKYxRR zgCKpJ#}U)~B5D2>Z5G?jr@eJr%@5kBOttM=mtW#0qH0}=?Fv+@0;)GAMmflFe(;YB zqf7ug3CMW4;lFIb;r+Sh$*?bCd5{zgykGho;8-jfS9QWw(>sjJ|F)@$Q%o8&#qAl=!^4I~X1x;`~?PKj0A z*Bm=_WFORlI`}UV{am%#oz-iiuZWZD!_Fsg5K14S<}_P%q%iYu&(C>+Zq}UGM+NAA z-s^3$turmm;za+sTkmF$56sq^#{wjJkoz%r@aXHH0B?d@$z{yqVLWK|M?ZC3TKV}$ zB_p(Nu$tmedii6|74W$*VrYg=igXMdZc0M=FY!k;nRvP$Z*BwP3w{=yI*AQ@t~1$# z0*D*ZiVQL6)H{puN`dhm7w2Q8rzl)PwrP1x05=LN(nI6uZ;EajC*c53eY3tx z1IRSe{cUE~yn_LTmgt%%yPRPG>@@z>)+5-B)ZnPSb(-=Ww4A6_lJ&6rk)T)n8r znb6L|j8(c?Xn$=miVdJUI)7wyTgT^~gTpa+|T7qS#=7hSs573ub>+D|A zs9_t9=DgG_KPJOwyz_=5&wArw*DYa>FE}mN4%A+HRSpeke;Coh0u)2H*&r7a}rYt`AcZTTp^CN48#8rCUciL{_i6%whj)?l zabM5j-SJu~N= zWT^Q{L=4D0pvdI>8 zgp6)@lP~x*MpvGSL6i{Nr5S%c>o1=iLcrKeLJSlT-vmn*H$T`NWBh5^lf?f?&>TlB zR6?81Op>cj6f|ZQ!UA8KOmn{&Wxszd_dWylkseUXAl)wo-}_NFmsLLx=!SP(4L;VL zX<;Whm=Kp;6mVJKwp7~1Zx+P)RNJ$3nmn=0&1l4#(MtaZvTdS@Ru~3|T9w>!Pn_QM zj?KH?O*coK1QbiCh{AtRQr|>B>{{(+J-=>~)p-KN<``DAX4T`Zv$y6f75qM2tOy1Y z2snTx%~Q++;CilD@y#fgLK_Zu=^9KA4t(%MzL;cBJ0imv+=sUuz`;DyA2VRWflLm= z$asTtY*X!%B@MXvG%>|^bG<+bzHe5UkPw%yRJ|#Enrsk!X|-;svQ8%`8zB9GM8$nj z^4!97vHT8tB1fRu{@7D_PxEJgsl;sB$Vn6$Z-r*o_ zDkJ$Cr4h|sF{~8ef(6#n@XE+uM_P&qF+VITdDMb8hPoVgz~VtZ?@=GR;8B;mq?iWv z-V=FC_kM06va5^(lX~6NpT>6AN6BkB+5aWQ;u&K{fRB=?T19R!aOJIm6d%WEltJ%Q z)16CzqTIt5&%PHQ*+*VbJbUF0BSS|lQ!bNZ6fS6-LaFR%|NI_3=3Yxb?=T;hY#ew&LDV5!uC3+iIQ zA)w=}zpK3+C2shWWJ?o7D!&4n%*VQ8I$M1imk}?*Q2sxi*viKk)oFd9vmnov{gu>J6X+#jr9y2 zEEl)V+$5tW6%ux#2bnrt^q-jJ(VA#Z(6TXNtIwmgL-*d2PhT~my!B842ZVPJ;sG-> zfx3=(`STzO7!`*r9#F$WcpsSY0lloo*VixJYv48FbGI^be#C+>ZD=XOZhxjdoH^Kw zGF*0k?9p=P2XLMEKz}*E0dEoe^NxV`RQeLb01orX07Q=)2WuIFvE4~;#s_sbMUPTd zuC7T)gy9I$tPq7}p~Ir$^b%fsq46tpJgKv1mE@R)2lR7X(>nZ|C zu|ceY9e4u3yE z`-}M52oF96nsN#?UW3gE&&kE)TPW_!U=O|j5INoo4u2Khc)ljwVFN;D^ft(A4S;y) zW&{vvk;?|u*mysA_b8dY=xP@i?8BC!FD!KY^Xyl1UU4s551itB>@1cuX^DIew&8hi ztdOYrrbvYbMz?C@c&lsI2^KhP`!Dnc^N~+5u~slr_6IR?f}xD$ZsUQ*XhN(7;#7nI zaGQOm2N&2WxaM_)@y7?>b`)N`8W~*MMf9tqH^MqoXEoyHvr$uF`|UkaE#PyH zeMG`O$mz!RDH4PJKe^RkyE*T#>FUSZ;Z<~|2Q)ylMJ`Uc` zA69vyvOHcQpN8lHFF>vYpS+A1p#H5FWh1MN07 zndeE32qr)&f>r`-a*MPGWn(@9AZ6KRE@J?MqLMlB57ABE1{w)H>84{^G1-fvew`sC z?uU!0Yj21MsN3NV5P?dp2LUBW;YMVVvP;n^-VglN)0}LHiGq$Ts)0GKKm!%^zXm+; zmaS&lAr0?vmIMU#DE_YNTR(}9UtRGli_eVcqx!MCAZS60irvXP-9}9dU8m?rxQ=-FcIPAZW&peWrf zA^{A|D*2$|;W7v2Tf7wwRkn%vx4^Gqj~|Y6^ILGgmBU43V#dRYWEHZxZ!DZ-u=WTE zcQ(Un9v|A^KLl`GMIgix%K+5VW6+IVibh6Nuoed7IP>MVfOBn>8Elb)^4$F^3c6_8f$g$RGEL7qJfUzBJ`M7Umo(hpY(sWc;cX)HL>P!m}$E>dd z@B$Z*s-0+T?~S!SIumYuu#KLyHvP2Cl^zql>#qHyC|gDqx1Kx_OHy0E%>*2)$ckYiN_;)!Jva{mEL?2`HGP^&Ca3% z@08Q>?0bx1838D#2k@2^Jr}w-Vz7=R1%eRuYG$%Cev3s|{4*G?5gO^k&_M5K^(3@W zm6Cp6qN;*977k8F)1|xTmr^e;eH$b$bj>CMZrZueW}0RtI=kaFr1^5&#~v%11uo6rpLnZFPQs$|DcnlDoW~ z%gRZN+{XQkT>Wez9rA)+?i3&nXlAUj?l=jz)%NlF;y z@bKmF9;10;w6xEB^SY4*2kXa7(?dUVBn{i|uqMb!T;(t57m6#Tq9CM1eglj8L^MqP z4r;hS_G@Ow_bnBIEOnIUTaLgSkfZP4c;8j=M;M?)-~SFn6wsWB1Zz_X^x`8Xv0}~? zXB1Ux5pT=O_8>c6dR)X;GO+K9%t9<4QXRDm5mC!m(#MtDa8YaGBF;DFq9*h8V%f@} z>5mk^@=sT-h{=Q>f>ZG0C|&zx&V;l(I*nv=O^pmD32y3q{)@Z|9`o^cz7`0^w$*VE zrX44~4GWHl$cS$PXI@R&*XygRt4H^{tg0BrvmNDafe@U;@}&DDTRi)uCnr6>ws0SL1O^S)xXB}6Liw}6-mC{K~3I6`WUL+6yP}2|t zFWUR-uy%Da;JAjl-Z`l<#YKPV|3qEb8cGLde-(>&C1x6Dg#W7W(ZC0vNZIgwp1s3+ z@BnzTH&Xp}NTw(V2es6XwFnL_elzlqFOu0^Olsk-pF=2pYLXFpmDZ69C~PgX9spkB zUdG3*HMHyxEd`CxTFV517mmjmyLKXU+%8Nx=V3t*Q_zgI zdGdy1wDb{b2rm+!dZ+ZM6dqi`qL-f%O!AG1q$?Lk*_I>)4)7uRJHwtf`o5#9&n~Ur zt{#51gbsl-nOvT|7BlJJu?5MzT2oT+x%uy8eFfn`*;6-oLjR5H;ojHAI#Z>zIr@%88yp z+0m$E!P%JnQw|AG=keccnCM8#^lr4+3}jdfvlJG&{h@4JWN#YPsa9Z>E6T$syTBK# zeD=34$q!u@keZEUS^3=D_-=3X>jusSlgHO@h`KGh`3{vx5JZoyuQ=9PIK-IL_vg3z z%x=aw3?>uj>(?%9ogY6fpa`7#Gu}UF6U_l+Kba|-+GWI#+Y$qPy`O+wER|mmvdzEu zC|k9-)qd3=em=sl&XD)K5Fcd8c~k=OZ1ElJm1p(5PkWP=cCr`%Vv@}>UVQjtQVe!c zmDfK%!{3>;>+JG|gGNai3K)y>(O1 zB2|ya;j6xtp-;jsj;*cy$$%ySbYKs-MYYnAf*nBKV#pr_w?cShtS2h%Cw^QRi15GDq`N$psP7Mu>AU{*4i5H(Q_1|MX=lb>ck2J=E-fa6iC78*S z#++#8RwYV>y^M0`I4b}AEb;m*EMK=W^94$_{%})67_@)IV^f}Ga`L1CUQ)nk807>c zt|pBDVTngp)Mf&iTj+7nl=2azpR%iDDVp(jYQ}$EX4M zsY9Xm7Sl27z4B1%vB8tSB*47#n;VuaKWD~?n-h7G)EHs9a~pNsYw|%s7zoYBl7pqM z1fWju^}lbFOIzDo`2+)}mSTd4M=|-XlrTgWBrO^)(bP_06k}D~Rk91eQUk8UGZ+cNR;H%odK`dDkP2%#GzKk0Sp7*$ z$W6J;sz3=Aww$hj%FuARd08zaAUDNFL2|;Sh%*=3ad~3<#x(HO0_xK4&o-1b80?k& z?#HuY+mqF9;~>*#ty-F$1b#cRxK)N1tt#GW=@yRS(hB`9@<@5NMJ_TxTDv_bPA2+O z#v<_qkgtW#E8zom6sB`a0eu9W64(+-e$7_JVVDtY=Zl0?$nXstCUU)l5Q=~gU*dME zmp(Llr6a?SsO7tLsEUV>aLG8%PFRc>oW0J6x2)eU75HZ3F7@APb<#UW59wD$312S+ zPon4R;4OlLfR|#;Sh4W$Pj1Jj8;SG?z9@|B%?S?0Ut*xCRCW6^?ku!Iz?z_~5D@{P zFPmsx*Pp2D*_5{tgBD_40Wq@DtK)JwM$W=Z(u=A#_c>Vyj zyS0a_3*ue^7JyK_86GY}HY?->v5_&9+f5uCD2U`;2XW+Y)-If>QVN5XL`snK^2IUC z>oE;-XKQnj0O|tQN?7|)X`t>oZbZnC=l781UOPbE^ZB@ZftEGS)>%$>z zgGCC)WM{T3P_~vnTxD$nI|R&-$45 z7wx+UKN>7tP+22hGoJ!?mnO!=DACL6!V3FTnE1{9vU*_gQiw(gy-Yv06Oe<$wSA{{JfE;IG zph+KGSO9A&E#U6QiPJkZ@Op=;RVgJPqF7*dawZ;r-dc+M6?i6{8ID|g5$BRpdg$=s zy`%C5MBBhV@@pgjgPcqyAm769WcoefC$Em87bHF<;ioJGh%ItZxxW3&8m4mZl0v~& z_>gs0nAL1Y(ZQK%Tz}|e1cgBEI|YTH3lDE!Ua$;aFhp)B809!m-*?!eLr78!pgF{Ij zRx@&fHVyzn-)2ulyy;sBPNV8r_n9p{OjzvPQf*w=A@8x^OH^J{|MA~I=GY%k2b4M% zIR~@c=K_dpE>7g`ox9jGwGAIAt8pm75M)@}jOP;XX9wjJS+S<@`R1LNM;Lm3JwS%= zY!q+=G7*TNqtm?jrr%W1;-MxvmQB6l3FKY^%X0^DGt&-fpkjW<8Kwx8n&un51G^;? z=~Ko{eP^!P-pDZl)~3>PVUqMU+xdNNb*Hc}dzs41e`o0yv%!S)wuX{^XU05=J<*Z1 z))wQYlYLcpkiWF$UbsAvd6vL&3s9O)*#XO9{wLg^j~$TKK|V=g7gp&-|v+o4Y$tmXyZ!r z4Y5-yn;(Bdey~OfaagLU$}` z{;b$u&AB{6KuX5@2Yvjf^6`PO`oUuhb5U4Ny8OMH7oxDI9?OCEvyEN5ur*2yb{93t zesnfkp!CxB0pWq|E;ir`E@P`V->tH_v*0x%9jgbr-w7-S3d($+_5D2{#m?i_?ERl4 z;>DmA3+}&bEJ(D@5J&@Hc7lNe#~-wv{cdNgxG)IJA3vn}b>6nTjynE&cu^!>anWr> zpa{IpiP^{EkcdHLiAW;4Q$b$%rvucBarBUNM10edx;gxQT&$Rme^T@N^dwuASB3v| z&iVQ0*q23qX$NB6t(PwD=J%Eq|8cMb!(Q$C<&_M805r;TNA0o!!)!7zR}yePy)2gT zfwHplA^C6U1ttQtIKbYk;|>4gZJ7prKjlHqewn!SXU5hP9zgi}T40U^G8oyIx~dbf zkuL6Ssqvl?zj6I|e3L?Sb~j72u!D3Ht&0v3mAzVLoV6f8EG!h^~n6C$9pXo4UC3BEx{%b6}J?6l1yR^ZRtwQ?*g=H^Bo z23%p)LCqMQ{A45SN#t2daUMVYdfhFb)|cJ@8{U4-08+$YQqy{SO%++?gStdzhUBwO zV=)i+$nb;ZMZP;6W2P!uCE;U!Q;ed)-pswl3b^B!6PghfVo zGby-QX`P?i>UN2CrT{Ip<7LE(V}Uc9cC;}(ZL_@32Lu&iv3H+XKzF+_7V|a&>BuI( zUQ7^F^7J$FGV4Ee1GVFE2K>5J&Ja9G^M#FvmO8obh)FC9M?7GN*l0Jg>!p`lqmr1@ za^XG&)Zqq%sl^BGNkZ|*tO}F4a2irmuxNCZ7dd!>yay-}7hVM=PC%%W#zvXLgXPnO=G(vFSGR*ubKck>-J}Up zL_@`PKnUyR63z|2Z-ExPgT~gnROzcg!BOX%X2nFW53sKtn19zUB=sd%!|)G5gp_&n zK~?1lOh^js=58icz>TuM@`2FDLo}+D&LY4qVUT5MUybC;G=@s*p6SshbpC>?iLEV; z3@mLXSj0K>R(O!T&m4$GpGAN`gwJF7--mx=sR3sYk{J&@dB;`- z<8$ZeRWs|=(Hq+_O4^oD#?6~|D~4l>PfM{wg@iql1rM)cZT_x)yfH=ExB?^K=cWk< zRPnGD6J@~#iy$c;)9R<=`T6l-rpPdGNJ2BMtM0-Ns9X6z^7sMypccjbCH80r zrezEX`hJl77Xc=pn!&^LB88S`i=yQ#=L_)>P{7Ky(mzei>c%pgH3hz@X7SWL2Ef1kx!>X98oD1Yk^2acKJz#w`N`kZ-eT;@M zY4Qp;wSqOOKQtt=ttjEvZhawY993D0Ov1dcrT_* zxWN6tz>SXiDAV;PKXlbYJmm+mt^Q7kjv6S|v`N@?s1p72KRUjUwcvSmR7mG$0|(O^FW$ zPa6q*n+U-o++KIFGg~5RMgOPaK{6d7aJ21QanGG+74zUqv?`f$)D=00zD4h>sn%v1 z^;7VY5Q3p?uS)T6daCCQJ7~!@TeNr%Uz8nS%?fl3%mas_ zCO`DuFXl$uTAx&(QrW25LbE(TCJEXI+OO?4 zPE19W(EfT`7Wwd9-#{Q`-t}wJI&; z>Y3ILcdeVZI-(Uz7uby?o(q0PP>40AvzI)KeREU$+5caaFt;pfW$OGg%J|-STf~7v z!Uxt5}G26PY}(0`sd(oF>+lyQ8Ng>Jr-X;*WV;{Zbj zwD;vv9m1TM`e@G)&)oSpGtKskVdY{)R}L zm8X&Hay8TZMhlUo^9K9p@;C=`^2R;CprxpQN`+0mAO*OWYQ0~W-E7I{l$U#(=L@?* zLYp3sfDn}bgTKX7nX(R%^w$;!%)1_6H(58%?1_nZ?|(5li<);G8(>BDeKhv@Ev|Bz z+@9(oGvhSYAUEl<)7hlX9Ms4Ya_=w?t~C~P7I0AVsMgEPH+80wKK5z8{r0_Trh)X3 zsC~;Jf&C`Q9~Ox@EE`dx@3a4o2oA&RnAOLn3uK^o*8W2DVwIhpVOpiq%{^WB0q#40 z|0R-~^^tY(k6E(d&4elxQX z%7$J-&5E3t8iQ(1KDd|0wMT3d4u2U-wL}6H-VP&~#MvOp37$4*MamA@pMPGD-8{4B z^@5`D%8%o46cI4+R=FoYh6a$o+Pl{D=uzlkmaq9k4OCGYD62A`mBX#h>5EaqkqJf0 zkBkw6Uwb#6RvWw_yQ85n#?~@d5}W`OdPeP92s=wJPL1|-SYqV9hdA@lu((&na|-07 zF{EZz^Cbq`I&e6m=7NKO2sO4p-}uu5vKxBjX4tT~K}Q?pR8v`c|Lc0kFum$U;zKn- z9HSkYb`UfFMFjcFm!y}J_BNrnE$pKM_kZ?ZOOnf;&RI1A`+!`D-RSUwh1c!qW#)I8 z22+21z(&AzuND<@pEicJ0`;_7fmXtav#5O+jAM+NN&S&t0qzG~d)`s!+B?;)-e>41&9d~i7?&lTBGWqhD&ceO{@*#~ zd~Y8rT?c@=l0uU1PZr&Bc2VBXkqV3CY z(V4o9i32g|9ghM7j+%9uYZPybe`xZ{o!nff)9zm?HxDKq^}4<9n;>JbYk*r$DEK*mEQhT??q5kX(>) z`6%cfwqEBNVA}j`!@WA_mCHBaaGvLB-tf)Vl)2{9cFEW{)c1a5_GsKEK3t3@X?uoada>AW%=Yk31GZWNsxQy61ONXfN?7<;!>cW( z`CaEehIe@8O7#5l(`)zwz>x(a1Wx$Vv))2#nHB<}+Ld8{>j+a|b%!3ga|7_@+LJA7 zWcol-Xa6Ji-VCWTw+DES#BdxJY~^*fL(aJ;SpSt2Sg5|Vyu(bRyyh}8hrfxL6IXx2 zI)YYR@e?;=(Z|C&@LF5Lgs_vEB$4xeP86U7yPqhg zG;n|w_~+kv7puP|4F@TTKcj7&OfQ5-q3wwQjO~}1Xyz5?=FieNL=_iv-icQCaDk@G z!W4IGNj4Gq8{a-)7OQRg(y<|5=gJBwNU7?5 zIEWF>pQf`=FEH*;u(D}Z?QBGE94JO&pny9yA@S_y5g2V->XE^ z8G?yScWi%4&Do>KZ6crgEv4V+ot)=en1n3E5?+06*TNdpyw)6-BgKR5#;6Z>{js-7 z@n!$%6H`&0VZ~Hy{2&GMV*bLu%u8>!H|9?mmtat7w3`3M*KVcunwf5f-xfQlJgr~f zm>24ko4&CY8HaqdLSST^sHOQYpuiIOE(UMy4pIW(!-br0)PWD~_ev9@PG0)#jC6Kt zI_8!qHu4>eOVj!LdkgsCwbhX^V2Qp*UtPaeCk@I@_VGTuWt2q8_#{b^y`4KUibD2wNMxRQxbgnp_YdF) z-tYJG`FuCn6rbUl0|4mhS=6?j6;-vu-K{NNTpq zxDXo|H=hrV2`FnH;kdhx4`Nk0VoXx@+^m4wJIJD^3+XHedintF)%u60*a8f8%rj5) zWSR-UZ52LZo8-AP9!%lp4rB#DSU}bKKDKo0*8yD7|7*^Jqdym4Nw~~E`NI`^fpPvGzW6sub2`tfA)KnwBGhOe1R$Uy ztG%^&t@cLnSi{esT`K*KRb1rPr56z3b*TdRA+y@TbobXmV1F5bV*-?D);!faDZ{VS}KfL0sMJu!>y*-nEhyj{`Ok9&TrP$KJ@AD8C3j$-+Ehu!RAPQ z-mST|1h@mG>ix$cAkr!{T}rbF`ub^SQ|lpqKi*ArLQogJa(J_J;B156Z2UcgT)!tJ zC$PkannHHrMh_mO-lZTD!}S5L{uzlPYnQy`4|SPa|3-3q^VQ9zlY@V(T`6)t5fHRL ziNBQpW`A{AhphcBtGaH4ka=`-cHgZI_a*!u;`_$Uj*>?w-X0sOvek$j5{3Y2Zo>Uw z*OdQU+d^3;>^e=kr^DK@|B3VKAJbL(H@&m+VK;O_DJG4M^qB>oPwIh;FbSg?0>KBT zy{@CwKXbrRB$&b&!cQD7F|k;iV#Tj8eiyHJi+>-T!mhJj1zi!BR}T_`VgBdOrXY*T zuf5M*Ka?>4y1WuV$)d9#vei~Mu_N46cDe|_BN~1z&X1!7Enap*Vje?K+sIvX{`)y4 z)GxwGY)JNfSj5iE!tt>}!r9Ps*Ou)Xzw&dp7i?b54bNh8TXEX3kJf62mN<v_%q@h*ghc7(T4r6 zjcxat3UP0BsLJ-GdyFE~SHNV6PDOTcJiq#`*(*hIWePFLopFGb}q$Y|3z`6Yy@ zkibb|sF%!d?i5KmxFLO8dN6}8R3otyz7ktN;PD_Z6WQL72 zl?-@S>*P8dpSYjDdMu^1ccA8);=9RT5Z{v9kCbTP56kZ=wGVNMLi#{Su@c8ygj1`C zzg!uPud95``LPw8R}E|d&*wGSbBdL&?&rmB-qZ3&s`4WRH3Y=LWE0DR9A4zlpVQj- zSp77@SQ*$X@$$W=xL-Y>Ni%G?ib@e59y1S!+X3@Djarp|7h;ROh-B1@Bnv|-SwoTAi3v#MQNw5 zUaGnp_DY+vZo)mRp&EH-bA|?)+;wW+atXEz+WdBGmz0#$XjNHPBH*y%cMyvLXOaLzALC z;x6x`i7!Hm-Wziy+m684U%Koa6PBo=%9G)f`c_aA*xMTZpD|S9I|TH}GfV}Q@{w8L zXL*SL_bBi8VgiWQ$Yy6w4J^o9KO}e_`o5!|AnR8OLj|F`kpky6NW0>LJk}_=r>sdO z8t#%&e~$RwE=eYG1pDoVSD^q1D9oboO%=cq4$Fc2-=@iZHNl_AW{1G;C0on+L9rhd zM?Z|GQj1wZvU9gBJU+5FA2c$VbJ+(yb8)WoYJNc6IiL_LzI*LKKJhH#3xr%nGNZ+gm`Sgd@GkRy2faAyaGZt`LeCUY88(S@WS(rEnAuvbfG5_6Pz1?YXr z21u*txk2a}=U|HE8-OnVZBF2LuCt%O0?L8=!P1s zdGNU)8;&1=E9C=MHinAfUx>hJU5PG0P$w~75p>HZc7Meq} z2wI#3PJK^I)>e)O@f{}T7~$@mNv4;_UO81Cf=OX`&+pXKyyQ|k7_D)>_q|}(DPA7n zV#bPdyLh5!E&BxaM>J8o)U{p6Y5D{n9*!EJlQ$w=Ftw`IGnn z_u2AEW(HCst$Ocb?vS!P-@-3dbs!7?xQI(-dwZj*cLC)=XzCnE4u(e_;!%eDq_nGw zbLs-IkJ-=>2ye{6FE~pUKpMer?+lgOl2Tf*IX`(oba398a&LG*IgTRvbwJKVQ&^nA?}}makk)vs;T#g{zAqw_5kFpn06k1*cfRjRF(QaJ=%uLg(*iCuQ)uTFWKk+P zadoTitvbL)@XA6O(rz#9Q7U^k>-v7t_{s>3B_HT8Aa_HI*|CH^&qK{pBZcgMsB-q0 zE$qoa0rYJ1;RC1t0APFS;b{>Yn*z42Nfpi)%6AhD&+Wb+RgKtWQ1*}7zhuHwxZdoJ zfwr7wH}-y(8hheZ+=;w``akOrklonORs(qdunXD^sXuziuPOeGGtThcd-+Mq8FNsJ@0ifuz z_=gB66jVu8f{qrpt@k();-?pJJ%-{@oGbpUx|iFooHb}1re0RjT7TIBPKzdEKC{2I zS4ry4NKC9BO6ADBdiLs+{Ww^6mF{HdXDPu7{KQE+;pk0y%rHoP><-A6irKuVI8V_Y zvl1qE^T^&vv`4N*pimMdTW(d1n(%;O$T69njDhC~-nzyhnEOz*3`))!w`}O!Xcw0( zLGD+P+ozYWWzuh*1up45l>|);6vI9mM(yazPgMpvzggH8t_7Svzh>?KPVe(`MIQ`8 zixZKfiXdjh`ZR*v9G>%XFBNHZZ3r+^%U1$K)H4TFr<90RtvhPfpxR3T3NUOWDw0Z5 zC$+{1%{n`L4gUd9{3h&pl8LNl6B|-R{)_7R=HYjg5K-t?2G&iEED zgm#we_rJEY#zkrMk^! z?I?G#5ct!9cCh$vuS6CFvOH{t|2cOA!JatDy{@yJ`GiXphjjkrlXnOftGJZ2XBP4Z z=Hdb^Bigq`hz9}j{)TEjuD>@%u7ja<;htJ#bnbQxuB8_p44D%A4? z*p~?uO4&)^x2Tj6SMgqZ@lW+zi?W2KdG=@IXHMSJ4NU!57#C1sZ!Mrq;V^elWiA&B z`hV|FUfzezCbG{~`AIs?y0dB!o!Vl~ySbb;cpG`iw&$qfg&32|JORdI9l1wF|C=!> zm7Ef7ooT!c&36;diN)s&`_(TX~`1Zq!jSE&??h^9R3&G$$JmvC{~5< z`51h`Yez|gT|WIQBFGvx*^6jl5d2f}*k#a@?&At@j8%(;bEkH;%mL25b^K0P@s7R& zJh!r6RJ>{wy(GjF72`AIAvQ47V}9;ta!X_m?rQurYbV6byLB6149<^^Ywj>J}4DqxSHNH(e>{b^>NXf zcS(^J$Ae2N9&_rj+fjB3S~Ieiex=SK5kVTGTqe=d5Tv#Zp_}^zzu)`|X6+aLV;W8% zYw0^5&R;;F6Icvr>W>0TkIIf988j172V6FsJyE{1rrC|N+h|?mw-FM%GaaFT0Afez z0ccz%UKI&w-OsW*=+kD1Lzxk4a=j?NfDc@NoKAh2qMZtoKOF>tk*5>^7f6bcJ}=R% zE6Jj(;+Pb%Yccj3r#_5v|*k2lz{ti9c^D2QR_edMVZIj0U+HqTCr&}inupB*>6FHe|>5{YO%?N%} zrN6VVzmrui*CTGq0*>&Qvx1!_E(Go=WjRa6$EYHX;RDYz*H;Ww9oC@2zDF7_&h`Mq zFDyw+&EldrG#OD(t?!22mWUtLbf`>Me)e|xDo>8_lh(;sWacyw;4A-)uiBRz?We-SM6KR>|*ceEvQ&EHZrG10<4MOyo{|zd72aEhrK{xA0bwgtr85tgG$Hyb;gWfb{Hta;QU zWUprW&^ht*1bPDQcWxSyB~%M=atd(z`rM<6@&NVTK&v31uaXVgBm2QCoJzJ?-aAQJ z`ZpoAat>9kB$J=7$Lxqa+VM z)#d>q+%I_48OF{FAB)lPp$y4QGqoVErO92l?2JDB4Z`p;cM(>+{9h3K<@EzC1lW#Z z$E^|kt|xv(ZW&WOH-BTU2L+jAq25JGc-71g?qCS|_Nj_scP(?9`n~2pj*xzGIgdu49E%A+C zj3g3N=zIY#AGahz!Az_XWgh+#XdSj9-GeqAawfcl6mhE|sE+A&35&uBEqvGS`_!Zo zmb0v&rgppT@Z@%uQcj)q>iP1<0tw#1EVW_6_f|_bz{UsaTzqC$bIlAYt*!TaO3#f7 zZtw~Wvz2e2dmdjo=F?4S_37F-3zPB8eivAuZ_|E5PsrklOwM&Ke6$`1$WUm{?BeQq zvXc!JQ~JLQSr2LDXhaM{0pKjF#%%!R(SYT3&scevzjc_ySMb#K+c*15=^U#rPd-Mv z0vmr9t?DG}P&2cMq2j>n)?xTr#=nutiFyyUjcxX}yE}v{b!Q1QaJ@K)k)#m)YX5Ayvvj_OafQUZ^h=k?KGRW z*^P$?D@}+M>1=c#G#@XM70I)}^^Qnr0kRnl#Y`(rVJ-KU!`a6nk)AYF?A~9|rOct? z?yfHWIy2_W5gr&=SG&FM1#cg^8Wj|w59KkPb}zz_asF-`WtEDoG1zkV!<}5EjK9xR zt3wsc+7-MmY%<-E`3Cgdu)vD-qX73#^Q?d>ww|X%&h+f9)h#yl0|L2RoIrO2)tKYT zPE<^TO~LN015{kiFk9g!PmjvAWJC`bF#L-8UOyFB;-F&^M+R5q^-XL(pVacVgnBi8rO*4x z+r}Xg^_zdwCRKPtZcZ*pO076YR7{-H{zudf+$Q@%d`BSuItjIo%DxnT;OaKRhNo9X zJ5$e@_ee`h?%Z-+-)Or9SMbz_H1>_K5bc*94Kj9w8WtAF98+%SF964ObzA8jUFET_ z1cyj6J1AT~CSFN48O>PgnRW=D7&*HT7`Uq6$Yb(uo9^v4bi5qFOy3@McB3Y_28*$8 z=|EJH;^y{5CEcnT&-S=1q(-@Ud!i_?I_!8DG3b_o>aF9DjB`CVbwtk|E_br12*dA) z_(p5;SKY!ChEYAT^(X!j^TYYVyr2Cy-HwslJj4aA@Fr?%O7d+505DWtt!hOeY;RH! zF_+oERFVGP&JS6nuVSnZpR;{U4Jr<59*W(h&1Ggv$bn08K&`2d1Jtsl9|7c6V-z@j z!hA5$S#p`cEHOgeT9h%T+mK<}JU(z9#2I6-rHG55nS6lJSWY;36h}(RF_4`Ef?Ng= zza7ipXFEHF8SD?xM8v*45)`w4aL+lyC}&pJvf?C>)T}m$2k20V(DKm0{set{4K5p4 zt*D0Us#RZ!Yr-4fFccl?m7?k2Z_h3SDDp6I;cS>i>y-=J3Ngb)ewj-6vic;OH0%AP z*|MfE6Pe{D(~N%4xe1L#X&@n($NXbKQh1erjdCQ(#SZ&(Q2+RGC-&{fZYABug+}zB z(iLpLkhSQ=@)Q(u+v@2-Vp?Q`K?M{Pc@e?ttYcF#;w9sWE#*tQKRZv?TQ@lHwi>00 zKJmz3#(6vM@qkYJMXKSNi_m0aHGhSS+_rDc=1iyRkRjC)fLCif)iKHA-PHOrha>!$ zodgR1bhI;#$+#U^Wh?+(kA=D$SI8#b4#3on0wWfvl%5UWyytyqbu0nm?R_z|$^pHtIz%`tAxm zry14|Y2?1qed{a#I2cM1!CQT!qt>o3eD_|27QQIen||ZE_0r-vQz4&Q^ML z{69FE`m-#!Vn5}jKq@QY3T57>J5}lU!H=&&&zJWd)@li#2m}@|!dfEVE#Eu&3J#?W z{HoMSeg@G8+H+{-fuq#&WOskO{U_;f*ukNsIi0oUDgD$s-y}8<48Qk}&-9^Yx;uJ{RL>&45L@Kx7}Hc4BA?44+>v;lUB{|tQ^Ah zOB3aQ?%s}ea_X`57pL~PfA(~RT}q8c5OGlTYu(KG`vqoivVA1Komt4DU<|wnMJ$o$Ey->(%I_4FJMhq$k#~e z(o-mEG`ffXnx*lI+-)ds0~Q^XM?dFA-=5!$*9XBOn-}>i9NIsU4_q_i0x1oV2-2I= z9%iOWR}xmj4)@+q)sDTMu{(u%Wu9UBj43M&pib)(_=3e*rp zFNfDL8}RQ3Ih)Vm&34Lb1oInmRQ5Kfv59Q@3A*FCp7S1vR?lU19S#=@^e3(_G1N60 zC7@sn8^Zn6E+gr=aS8U#Zu#z*{|Q#FAI8_eSyCT2b*@_7jDPb!b%{6@#%K~F%l`L< zJe!mxbK}YV?R^5&x}tCt+z|wE6Qc=cj~fb-quhULx$u+Lhx(`481TQoG{~7rjdJrU zn@`#$g$k6|WjQ3cA;5d_tzL7ws$8+ziD}wKUO9q1mxp<9U?HswrhBZg?hHS*g!1%e z!{-l`vZw)irfdfh?a}r13e19alxt$z!IA_S)c$u*Np^u*U6|4#YQtemkHb5)_p7TSN zuIIwf>If)#O&d_oXJW(@F62t>D|j4+YkQwPQoUC9!Xp!-^#%U{1gSW0`Hc5~qC~w`q-@fw1RB^JA!agsyljalE zO=qZ1!6y;u@2Ym#bql$Z_xVov{ZE+L5NVEDMqsVFW$T0%suA1Ev}r`Z9bL>-r; zI|2b3w%MD|;~okjYFdPn3g(#FkL#Ttl7zNXp2MAA8Rb~GF*vVgVpa7;hd!8DyfBrR zq}=UV#pwPC*oFJ%%`X{k#st>kF{p!@Bs>rGjVggiJB$G12=pE9 z%g@+3!6zzU?ykupYvlq6-DmBbmuzl}3a$_o8dIQzeJIW(=mKgfY);0<^G>57P{VX{ zj^0?!d>s|MUB2zsK2j~T3Ps+5pEMHq*HoLO%ldYLn6VKu54zXb!5_&zBX`7re!*Vf z2ZpSe@;Y4ukl`^)z(g~^$H4-)W!>NpMuQhrDqi}&-LH`yE3-Ag9@~UYy(rePu1+&BlQtfY}_W%dOQhUM7%pR z7GVO2ts@4-gvHND8IUt2x2gsJ;gKhMlBYaD`VKqxGA-!Jhfkxooki?X5+L35sH`rR z6VqnBOmg4epqrsqF>v6@kAMT7KDrQ2y>V+7U)oT2Qu+3(F|GP2l}fR*E9P16wvbVR z!k~>frHLtl5cK*~dl*9^2l&yWYH%hGwiZUQ2Uy4lO$w#aR4o6CZ88x9Ujb zNEf57njW|g($dz7cSh4#m2>K?__fuME_t$7g@%73f_I)rCzCqk?OPB1gF^H_`1Ei! zzDO$pC1Ih=ZmW1_nkes)f#9klCRAYO#V;sfOaUaSk31(yQ^Ng1FdU}>8uL|+j=R1V znPeWC=H+(6GtqhR)z)5)WIK-|o`{@l@jedCFIn&H-$-w^I|u|&UkR|(n{YgN6Bca} zxtjdA)`HwiaR#)TeGnSDIVW^x<}T9=scvDMYt06V8MXlD0XV}i--+hC_2%D=yc?gQ z@-L#1fIXwS*vIR$=n2*-nNJWAHR<#2LrnaUG-z~ua+3D%#piu@EfV1brFb3+OEhEZ z_G#`2T>D?m#OTrFlTDCDE9TNG01x%}zRoTjwL$5&RSY6z?|-D7k{(8(TyVPx}b8a0WUgKEev zytp)>X9Jn7c;nh8BuWG$$|?pz{2!IDv*ms33i6b=XYx8t0o8Ph#O0dA4SFKLVq<3l z3zA|vJli&`kDxF_pEOQbJIqO1xrQpf z&z9?>1jGz*Z|#C(Q?6t*R={r^s&wp3h09^-mU~{Z=n0AFv)(V}TBleo_JZP|qDvo` zolPlbb|Z>?+c*U7-(N@;$m%B@ZvJ4HqI1FTu-F8i*2@gH@)fees8?(Gy?M+*SLTMK zZkZWwrM4zU>}NcI)hBN&lo47zV`GorSrXL6o>4G8xQ`G6=@+Z42MrQLeVywhY3unx zbWV66M^@&{27Y&~4taWEZ6T9vEyq@hoGZMSSuYJvA_gd3%HVPD&yBoD!nd@ z&dwRWQr)DnjIe)9Pd^T7kcEFb)Ad3p#G60WYjj>%kN)4+V{!wm`mV8;p`pN^Esb>T(< zyHXJ=6f<(q`|_vAL1x)nB1^cy&%1RDR--7Ff8=)!PwJXFO=4cWJv_}g_wW^k!u64S zJNxDg>%LYC3g}jf=ZrD435lr2uPrhsrh~2UPy`3d`ERu=03uL-Evm98FnB>p`hAcS zE%i`v_bJmzzRC*77{`1^*&*5oYUup_5zeKr2EztZ&NUo6nNup&Q{KXd77}j4{B7>n zO)@cCtmr+`{&rC={!Tf^=&++K=@fg}i44-lSoCpz{$_5_7^~&wls%3et0e>u)=t{{ z_;kF4Q??<0wbI?H%_@8-SAVti#PG@&X959g+;hnbt8lmsd_!g*)z2V^d1E3#5CQHl zraC1^o=$Q{w6>K=JH%GSXJzP|5YemfF*zg8D>~}jCLE7lmq8f=a7^NLoQUm>($h9- zvDJX|?wV(F@oiXx>HO-jP(eJ8|V5X;Nxy|4rfT6W9T4A-AzlAvv`b!6z8;wTBvUwv4#U&VkQ2h$FYE4cwtcDUw6U| z&=rOVnMlKoc6_;v;mtsJWi-hQ%3K;!FmR9d5_J#4ejKf~9>h>^3()QGgAG#Cr?O%m z;B9WXYRSG^yUCuBHuN5eRAfsRi?yypJw;AM&VKLRHha3o3VLek$X(@(TVyRX?%|(NJ)qw8SG9qfb z*;qArmW!oRt+FVx`$tddpDa^RX+h9-zVe$f;C7RA%9Q98oGJ$EQzyhk0))!bk=@iWLZph*? z(|SP<8Gu+9;TL*PxTb^Th6Y9Sg*3}Zh|PMb%>fo-w;(w75q2qrZ!D4=}tmx<$fbK5q!2yegsqj+O#dq3~503goICrQ5`!A@bUy7}05CEsV&!wEE) z7B4g7L(3Qpvn>u@RaKX_A#ZHu=pRPpEdLh3dNGAI&}a=i?%52%tSy9tg|>&cLzH3~ zJtkxmUH*{%s7PeFYt{_C5(GUj0qJ9H4u|i3il^-s2-REYwOY;cfr1`I^c%2jPbF+? zqzA4>wvZS3dc@N%$=ql{JU#ZvQ(>(B?p zxE_dq^F!vunGw4;ZG{qdoOpNA#A?D1)F5SaVn`f(^(2f$C2D*z3Dg5;l`8+< z6M$O2+m4(N@jJ>yM(cl+i1d6@m1d9PRf!wBQ6vVixAf)+kC%xlnQ({)4KbEr`}T=WO5Ayns;wZ<{OM)=QfG;Vi|@WgwH z+I4#0>`Hjq%YY5Aratk2W$eOcyZPcG+`2 zT7rTAcdG3G&K`ja=4m!(VeRFGgK5N(nFX~6WM-3}R>o)bKto~d4 zvop5B(P@25%W96Bc=EahaQ}5y{1XEA>Xy6>Q(Q9miVfVDD1`tMpVg6|nIJ)9OWTW5 z(&__4j1vyLIEeFP(fZhaPV@XUCs+=(bVsBHT4znXZ zrGy?uwcLbETu0?23;}6PmHj+Tl$9Yg2Q%}AVLg5T!8e!@Z2a!zql$ljFubK+IVSADdaab@NUqnIR0850&BUIH2Nwc=|@bS^VVb2r5<0#^#gUOe>2=lY4Dq>oikyV0hy2P6r=L=Mrfzjv67kwcPDsg?6?Q8>5u?F&_6VvB_?@| zy_G57W10=jA2KumDJ|2(LJo*+B+XLK%GngpMUGN>knRteQhJDNv0KwD!~t~JzPvGV z)=sj}Gwc?n_Vk>=9Xc)o)bv~B@12i4{a-MMe}Uw%L?A`}@T-{o!*XV)ckd`OLfP&!m?hg@xbe^E6$Z5@io0eV~o} z*|@*fRz2o86%J&+p9V@nVMAKZQX(ovk26(_g~UF@2R+rwq76-s?1z8RL+SxO(D6BO zo*Qv>)u;1>4a)`~@hl_I3mIZSn*aOwFUOhFzaeH!=pmTUbGqkL`1iylT>ujGn5s=O zF9Mz3(z&0w2$s-E&hYYkrY#sd8%Tdn>LMLhqjT^AS*(tZ^B}OP^2_(^YWnmb}YJps^1gwAs<7;u6rC_l}K z>+$^qoPAePtgf)LiS_c#G$v&XGavlm8Wwcq*^7%?ih2gS&%kr3Zm#A8_6`)@*Pn{mAw<;ZNDj55!H-r)@$8xp+(O}M)`1JB%k9Kpv2Mn^0SZU};V z>SDJQj6AGy_5QOPe^MszLvEW8X{AXhCnRgd6IY^b6W&!fHWr^Bb}8l_^IjVL=j9XB zUF{?DPR4UZn()u(W>ge|Bgq?m6ZZ9}Rs}iX5j71J{*%nO!mKqGnJv#Ce|RP0?&h** z$_22C-T|+}N>~;$J-s9w&vDQRlRp+&lY>TY5D4S{u6QsdB9~a1{fm20>{HIO;>VvK zV*ZR10(UF)ArxtWXd1v?*4c-^2+>W1>hof z9YEU%FchHcus~_UiL$vlKGoU_^Hg^ER%^Gv&eT?ks^w@2jEqsbdp3= zoSS75Q`zEz|-y@Yv{ci;o$XVXkf}XfzwFrDej^Gd=y~S>7^)Ozi&C278ru2 zgB;{mCuGj$PPHX)y^}q{tdEaxq#RrgX(HaWRRjd&`2(bQd!AsMf7u^4L_JxZ*Nt@< z@R7H~8+s+>>tP5^kT|Fx@_b8k>QJq!DGrhV*cHeQCKv%5Gez8`c_!J6yIy#zb;rtX zO{lheiCR3=o`dWk6Vk4mn%rIe9Vc*p^@~1>SDZfQnlzR&Wli*Mx^Qk;I?`!XS~$98 ziGRns-a0Tz>m(CkiFoLXeaI^{p^(Nr{u;x}DAyYV>e|O-c9X91>149D= z=W3mSm;%D!8mwPd=)>;ydDK_{K(|^b-B?C`)8W&R%wxUii8wP0>(ysSv}5r|f7z2d zB+#q0K%i~6pu|UyFfIA)%_R(Z0WR(XL{^;W0YHM1k??Vl?v5&y{H*b_qXD6m12gxX z5`eCS2SrWG_5Xb_J*#^ZxJa@$bum|6nSRy?{TgczSXfDL#&S*uVizDzkJxZAWtuUf4a6!*q~Npz*3yTlA~i! z4}JB==+0mp6fLpjVSRmwfQL!??k3)zUq!DEH607IeI%ac>DejDa{rNs$1Gz`f-*ET zZ9ap#Qzy*_v(@(k{WS(lO>E{LQPN%*2fzUb=2kt;FsR}e%A1x#Px2a-6Zy>{+{~ny_ z{_nAeak}SoE(4qogBjFuY2@e^yv`&+dBe6Pcqd_~EdeiMoPav_DU7VtCCv9)B$2KE z-{XVCcgdG=&+dkSyBQXPaT4qxBEm3zw=v7uehD?oULhXyKE&zoO6xPuxEut_w&^L( zD(VvSK=bthz?iT&5A~uVQ`jutq`fN17@TQ<{Dv_Z*xof|OzmF#T{hmA&ifg8hv^+ zdX8hLwf%9BvO(m5sOY=-s`T>+;=vQ_3JaX_TXr?ZOrtNE+}SktE&fzWNmC_6jmOx4 znw$=69yAKi@>`U^{O~qw$>Z+4;<Nhb`(8ssx|9zyfNj-{ zt`E+;!?*C?3y;CR4XgGEtT(fz6*TKOU5v(&qd#Jq^&6S~Pw=W4jHr%z~hc+Jb@kU<^w zL6N4<0J`=T!={LX8>FUVjgCoGk+MAxdg8yI9rQ2k*yE4Q3A*t8Ci$&7os<5Ag*b<| z^Vp7s4xOew&qo{woUoso%jDj!$H|&KXD@K__c`?V9>x*b62v&jJJcNTr$d1K;A@ke zQ@_rQ0eEQcu3+1LzW%fI&hzyWriFWs9*a~ohsO->Uqf^Y=w-!`*t(qCC@j}GN=mJi z?zz14-2UY(gdm##eD9!C`ri-DUscXN+&;xn{Q6Ox*CM-|&TerKE85B7l~weMf92hV zVNWdUZWq6ZRI8It7juO0o1)hFhay2yU+__?+t<5GR{|xHe>Du2^L%CmH?89_BI0P_ zhZ=5HNUKgWcw4n+q_#>8a$|}O{x^*#!4;yWVB9ACl7d z+kB1vh>g5C!v0+^9C`6A?>phbT%qm2wLD7#wEu6kVpgl z(2+IG3?3d!X>Ov)oy?rGJZX#Tb{Ht^N|(AXL{|Yd0MQt#z=EZJy$mWOn^Z$Xf|j=V z3)7I;(&s&BlPg?yo_SM^jh9$X3%lniH&n%S8b!Dq`0BPP;p|SBCACzE?$+(py>qD7@0)g} zxu|$+NIkSE^QlXS*jBzqI9152fQkgb^Nz|I;f72mhudPEdzkQYrJ~~9$LfmBb@e0I z(KX%YPjz7piAn*nJA%GY(_g%B;C6jcpHyIwbJqvq9_7d5E7PN|4}+X4>?^Nk=?_z# zy*^4v8Fx;nlq|$}Nf7U3lO@H7tBgUDCF5{UY+gH?7Gq{J9IBwJk}VozE;fot>N=LS?J+ zB(#iDTqH>=o!6x1O-X_UQZg%;_4eWJT0+c=zdCo+*$pNzI*XHDUC-jKy}b5^md1vA zl{fsxy+L1}?I{%G(kp=?LZS12UC&IiuXNH}CR}HzS5(7x$q>_+cN$&1@Su%7{X*@L z!r!54`0dWs!`Abdp}&Nr>#LSSI}++u60=)NYV_qd{$jaQuDV9i%jfSa3`gNY(>6Hk z8$x=eC5l+_Usvan9;jRjoOIaaNtnP?8^Gtbg7@5_VaR}SCx|?G3(8q18aQJaN!}E{ z!Kkpymo(J0SeN6Nahi9$tk%I!X*vaMtgdZ(9{9>3N|*W_j$Rr?8zryfhFj%#L-e(m!~O4(NF^194^6iWJ2 z(y0#A)~+$JB~RSxlILsr?Bc(tA74cuSeQ02mt^!&eM-|Z1Q_{K zRZSUp$b0coPb_V&Js3yuO+M%Ak*~J%kj(n@m%gK_lf>9ivKiyDl*O;S7j2j=T9>MU z(ww)db~7Sq2PC6g?YfWs>9KKdzkFQ*QTBcB$6VL?;5_vH1r37$QZRITQO1#lsBeJr z$o4Eb<+ADfnc<=(Q2kxsDDL0suRy3`#6@wXZ>O#IeE7_0kwM+cV3DJi&t&h|&!0ta zGPH`D0=Gx64S&7qrCID;WM{GS`oyb?(7^9Pa-2c$uT_LIbnVr^R>VsMxNMFaH?YR@% zlLj=oGBZ5g&?imxTiCp`vQJ>dIj6XCRdoR@4U3Z&cx36LdG2Sqw?S5;PT1zh-9PPQ zg25y{Wb<#ncYQ&1y}NDk?r`JzMmw*WVzNT*8-tKBOFT~*o9YIG=Y82oOXrwB(WllO z2l#7Bk)GMqYM*aM1?G1fL%07N#amigJ)P3;nPA-;T1rz;y{2!@u%PYjZ;w^4jaf!? zad7>)oD3gSv1Cx7PM-WAS8ij}Ym&#xnPR5{+qRFQk3Ctu-sE=?m=92(BJ0Z4s=+YA zYO#k<&@jWyn?U8uz|xtTS}9fe&c~G#L+uhac`rM?J1|dwejLjGdS=(Q=EIW9ca`c+ zxQ#C`=-bLBDhy^ZnPVg8e8kxzjSz) z+L)>`$JlbshsyXQouSLOmDN7)+}B*V4_)mPE8aUiS$CBsNx^YcPa7duv=FEktO2n; z`5L}AMF{bDR@6t|-k$7DtqnQ%^1tKuOqS~x)Ov*c_*$$j^0#}@xY6UBugWX7oZS1pik0ex>ryaHAG5O5>$%g&pP=R%+n^wi&8Zr%954S_ ztp-1jrRLdTZ}?$j_4wNqV3T`q_WFUkGa9wO`=;EVE&JY{#n7+sbb8Wl-EI>p<8i-B zCdLv>ZyH>9c<$tT!p*r)Qwud*Q|p7xKS$+$mQ|vr{2WbSmnyx=mDSZ%dWyuv1S5jF zo7OeDyVW9A><1-=#YM^~YV4mB!XC={eHk+AhesY*8(NUel>EwK zVfPwyrthGe^QTHqt)<23e>d{OcZ+=%78w%nIkDx8!Y+1+m&)(T9=ODt)(Ko`owX|r zu{v zR26L$h3C@U4bt5pU6Rt>9nvM;a4+56-Q6MGCEX}3AY49>79<4x?w|Sp&YC&vU1#t8 z?AWW=LIg^f{YuG4Fbu#jm%o`H({}1J6=J;d{5xdX&Ltt@@BKE5ySw+~`Y-aiJ#hEW zAMM?UE|G$7<<|fR02F1Vbl54w{41pIBaP;(`v$sT(AmFeovw-^BW8d#f++qenPhlYb0`4pF`@-mNYm`(L%qkF^b-J2JW2ze0hI@Xv z!f><4&US2tjDN<^vLAgL#ag4pf!6?}@(QA2lop@lc)H|`>Ggb*)42Ihm9NUSYG0JU znoNH@G>yH3K9*UZ{BY4KpD0>vGsV0hp4hGgw<%7;?PTm1^dyv9^sj~MpXd9kU0XZ5 z{M*?XFc)(EOH%f@K9RXgz*fJlqvLH{11bH4v!AnbkV%tRJG)K@%C5!v8Pc66G%xY% zuYcbNAscEU2yRcD|9Ls| zPkAInzpDE4UIZZ|DL?i;U28LLM!BWkd4Oj-51i>6Fo1@g-20x)ZFc0t#3vqMmN(@c zmigR8*ToT}*ZQ8GZy3(1H?)$|+rP{Hwf4j1`G{g?QL#ZM3K#bc`!IJ-BO~Qn9YPQZ z{;&(e`&~X<)m*&6|3%w?j2RK*brb-S%(Nft($gwZr=(`t(xID!d`P}xzBh+6nW#M@ z=HQ(xMpGf2d<;et9*)R!iGEbdwQoBY!hUMdfOiTcS|cY>F>p5{vgL|B@UQl&bw5<{ zKJZoTAc1wMYX14iorfqDe)5x7-AN$KktO#2UB*QpJHL#OS}(yqHo<_Bd>hAib{)wz zE#3JXmYxpX&gF9GWMdsQ#n<=wXkuQ&l?+Z)Rond_;>^hzb0Ogu)ro+I8GGv?Rp)NP zt4Vz5R(MW+nOU#DZVG?w<&LCGy2uCYH+(>6IGBM4NrpJs`_|+uxMG)JS7B+mo@Jw_ zVqVrv=)EcpdD@{?*_|s-BiZbN0++Y|rv0jzM7;4Ax@^=eHdIAno;mClvhxDzB5*%s zjCYt_tOX|NQo1}`mVWZvPx?l=I}rHHaHhMY9pXRe`+LviT(qnU(LA~TaPOs16dfI# z=yKFIs?wKp(^m$zW#N~Q0F6}mtFBW`Ui?NJ@C3fmwCWz)3YmF#xZl%C^4<8}*z1|lUl$QU5N{E=^J+`Wib(xS0)FTHv!uM-+k1QaUzF;*(Z}x1q3yFohbhD=CTqW1 zOV>zv2rE6;bt15q2UmJ?!;128rrB-nQt}1UtdP9cfCY(R9w|vAWg#X=R?PCyeWXiG z*Qe}k1XY?2`f*?T{EOp)UAgz)%LWwopC*mKQHD}p@0)Sn$}(Xl>6c5+4KS0Wxbfc4 z>)|0A%6;MyV`8~a&m&vgyEmeTt>M+sZydgYS>fgDb74O?R-}SnE?%dg?lzpgFN8cS1<9

Wj`)hW5ZK=yrexg6K7L$afu7L3K9`fL~32!?DhGO zovYw2t6a0S#DgG&Ry30$gY)d{ukXoII4)IG??qAy8rc6qed`-++(SOLe&A1)=3mLV ze3;RN*gu`6sZWTPS+Y^1Z*=~{Q5 zIm4Dsq7lg~qxwRFtL^Bm;5H(HTW4%_@2B1Wn)O!vc+x2R`lE}QqjN}b+xcbnD%O7U ziak!pPqW|xd@A+@ItNa6yCjyqWdAvyVw%hNSfm_wX5C{#{<(wbZNm5?J79r$ZR;y7 z;iLTTDA+z5l(LG#fo^i~N1Wqg%S$1l^gmjUF)_{f_Y);P#1%pby>%{P;W(my~EUO)NxkeRvYNhLlq zJ_v-ib5*`tB>YJH-3JG>1`CB1vudIqTCxe<+VmJ9snv6c;XOr?hhytdvaF?&wI{BB z4{Ve}0kt^y@dtvnFPv$Gc;1M0t1Ydhv%>SBGPdC;H92E_%q?}~=H zHjT8Ilw@@nH>_%-_3M`ATa}J)sNmX}u)-;4qAazo_IOoQh0JNnwbLl4%+gXZ{D1ru zPF?Z$QDz)91}LPhJK%}N58dQk_n=_|*EJyqMjXt%QdaQM9$}j{bBnu`MP-(T%=4m* z74oO_`KLf-0EqWJv3cVf(r47?U#D>$6MVBU_?=Vehwt~8eMoqJT=dA zr8J<^7N%lFRRi-$ETgb>bl{K7*nILPKuY9*m}F?)m-ibnhi!R(FOq z{?h>$$%1F!xy!31)KkziesKD2^>>00?mwHYh`P+WKJ&dj{99uEwV|`U-(HnXSpPZF z)2r0{SUV2)Yjk(%+`Ld4j#^<6vtBJ$o8sL((k0I+OFoTAVub3%pe59Nto@l0SzQl} zEsEgxJW3j$2QsoVGkZz;1GT_|m<&gKDrT`%+Zo`H#q$Q{D=D}q0Ivxut=*`iiZ~nJ zboAj2$~XG&*Valz5-ohArk}Ojw=ZHTA5;2!EqA3HtRjY(nrmbEZ|=_D!8Fzc*9FJk z19_W23z*4jX?aPLpnNqJxf0ygOl1Zq+)ou!_%Df{Y*b!<&;~YT4w%vFka0;UJRz0m z^R!|?CPtQ0UE=_2KB*rnr{EH?!Qxb-CIA`75f&!1AIo; zk@>5u#X&EvSa5FM;a>xWo1E$CaV%hJdZeNKMM8kPfHie^2e>V9XLL&~^0Dl1FVxPz z;Mt9^9XoFu0KQ&4F{Cu+reGIf!^NVhE9A;tj$91=XQkh2Z*G{?){7{s91oJLO7nLQ zJ8DJjvcc6ZQ}E&(w;H0ihL$HnVfA;iFU3Wa&C`VnVXeZ09@kTSbc?*c;+p0y`&!b! zD`9n%mx>vW;A+CFyZ8E%Hzg$F$b$YAV;S94{n_ghZ#o#q3P4WIXIOGpPxjwhYn>Rg zaOj6=;|+Fc(s)^9%B2}(9j;-pR{4VufnFuajG>Ly>Ei&h*!bM2y^05 zxm0>|fF%1Qdg_{xSccSQTYpvU`F?CBteNdxYe<|2EJz6l+5Po5zpWhF*8{nU*Y9q4gD@MF<;S2In7>L})eUpa(A02hAhkYoI7 z-X}mgAe7~dNftH~{Hu=9SwqBbJpQ#Q7e}9?nTgLv&S6n>U$!qHM02AR27k1UzFZ*TrI$JQ39N>3sJZbB0Cm;k{`{>a<@#KP3#e`@!2A_=1;Kf~*S zc4qnL2HaAcerayZ6>z><$AoTIf#D!MhPeN}((qz2;m9h#ky^onsM(%?l+E{zvyy5U zSh?`4+nMq*3F11R6OGf3E5@S}!@}6T4d)(bnIJ&RkwraI-=-|5Q_0Uu0tQ|X(cEVq z_&l5Nx?0jx?x(M{3Qd_Q(eLJZSWal~y~ehc1a>DEMcD{OJ21s>5%o76!HPh4AN^Dx z{!gm!*H4zbdee_r)~sP+(Lbr}J0OBRi?qq)bAn(xS>?FiLU(OI!j1kd-;eOJQL@=t zMXx3Wle%XA9|d0V)`eQUN)OHDBpLf|w63kp?@Q{umYTdshN)jej3JH7| zWj;6gtzrv*&$B9Abu1a2O)vL1QtRA^0c4>B8s^X>i+;qG5E)a{@)1}47gzDE4>!15 z|H++!mg@caqJI+;sKbPL&^vR!omd6kOpPwy6FvY53n2KBicSgpw8>SyIYb`ztlGo# zJ~+y+`cq0d-6x8Jb)Pn3+F!@lAmB1rhj;pDd&HXGeE4;hLX(-F%<-j}0y#^oxEYa6aWI&4&I_VgZNnw$DTQ2Q2BK!I#Tl|dDQ5|nlTK6~cM*K{9fc+WbC7p85gfJ)4$V5L7LgMS=}bv${18rZ9bcnG5y(7)IP z0l<+aK)p+5O2AAI#%7dIy^#8vVbv8G{HUv1v0a;m4I+birhyYDtrr&3{)PiWJTA|9 zW(aQPWEucDPa}}EV_umcGJ!to{--4a<(ZD79=HWcfT6$OQ>jT|3;}tnoZZie~E{GJ)Cs)W*2{1!8rxBL%uu6LFoO(1jrj{MUE1kN&m^^i^ffd z*rBgQN|LM|YOX)R8u5IkTWfH!qtQshtTej4!>TWR_Axd{0wj`6j{_2yD!gdxg&`X4 zw3wD%YZ|S&Fj4jBJ95c)5sBHhRO!eb)Lxd zY#MY>y`Er*l!A#^kI8Imt=KELG>h{ZH7T4SU-Um~3D&HJ!=A{tNT} zbQlLfdSO#2$WDh{m-VOpI~S}Xe^NnH(0;VM`LF?A;m@YwKrLI{UsU{XcW(nN^*?7h648UpeJ|!~|THrGtTo6~oH& z*G;8qILLp;KBE3)Db$B2I%BaMK1@PneV+@Bq)Y!M)#mcTng*;04St7*ZS6}9GvOAl z9OTtehyWyG0E9Thfls-sM2;@|tLV2O6+9CmyrHA0>l*U9TBrN7FG^rC^l!CKl)NM! z@tzd$!$CtFNc2q6yn5FthysnVOGXrv)k-_&drY-KbLo;X;}H!zMF(*R@HeLEAcxTB z-fNAVmEr+PVV0>17PW~AVyUJ~#`DrJ3|x#b{yYH@rdngmKOX{L~ekj>&Z}^TswXvA6`JoV|pX$7&k8C_9+bYoUyKo}F=anAgpCW|-Sl6gK_K zSfS4AHt9Ec3pSK>_D_HVRx)DRmVc)P5OWF&#?H@ZWypW<*XWqw^ZQ(N1ovm>wwqdj-&C*!!Ru+8iZWJ+^RdM+wt*Y zBMp5Rgd6iV>%k>>M{uFha}Ry$0|br`ZG&!{ zaR5Tj3QbbN@rPmg{JN3!I}5_+6n|3gq+m)|!hSSYj7!m~L!B_A|7sN(fUdtC3)bP>c=QgI9&4ZiNL&>Qon3HKs&Mbqu;C!=dCU2}q6+%W>QkO? zoPZk`MFyEz@pLpP)DI}Z`%+~Fk_D)9+UNnvJk`9kn1EdoaZ-01cCNE0Ifu{Cp8c(< zXFcZ92ByRer~dP%jJ#MxT)n8?!a1Hlnt$2eBG{apH==3RHf=$g{B7U z1|gG7wnTp$D!Lv?UhEYX*CHl5%Aj2R57%cPMQ+U*Wq>5uHI5R$uWam|^n1rF91?DF zZ}q-bcg>o^NOwd=t~Au%v5i0%Rg(?lH5L}Y5CbGVn6jM(fL_K|03jzc*8wDH26m7o+#xkm&@qV^J`Htq? zcJhT>n~#rLY9#&FRFHyOVo#i{W6p`nLj;aIgFHk0_^ujZpR=}r2{o4;FsvY8Z6qdp zL4Z6nZmPVK$=7PaAVsp*y5HWbd=946YPR@#onS?lZ#*J_v!%tTd|k|^M+PWVF~X#3 zGsa6HycKrEMqe+}$YrmJuvO0v+YWUkc_hLJ(X>4LvhIo@;#IJs^zXO1AZD4|)L&d0 za}-%|+^c_IfRU(0^xV%)YRO&~x@@qYa#)A3~bp zwz<7lbV9(-gPfVReyVj$C0dFP2N4%%*j-l{=O@k1XEFlhhby7Pt!?3Xg3Rn-ozz{?ZC6@@WjpDn8KWYoJiQm1ZL zCiEn>+kcHO=Z`K4AEm!`9RQP_TKl!}*wc{QvRkn^n9^ZBlU@N3u}-7!%hJ0HD}tCd zAA5^!L6R*^%?>~fI?%GI73WEvC!8q;klgf;R6+0u=y~e89}sV7HvovCXAKRmXBl3@ zei&qzKlB|?QJeS^35bK?QbAq?qubV6c1c8l^Vkf9($s7K7to@pQv!)?rqY3>RDIfQ z$KWC3`cyNX=>+vEnAIs2ekmJbQ<)In+nyQ*#OSQDzh*mX0WZeC4QDyuqJjMzRgJ(7 zw40%-4MQ>@`#lMW2?q&?J^o{y<^B3G3zC(LWu5In0^(H_pa<@@^o@`JY2z@^L_yA7 zgUYdoX}D&64|CagzMy>~Ps~uhqvz0 zHs0CRE=Hb_eM$nN0V!molfv$kiP?&zAYQmLgzOMf5DjHi#eR2DpR9Q(exOr32Gz=M zgfT~l+P?(Z^Z-FyX!Zaph+X;cF|{Vx@hVfckebvB0LW(LVN8hspm}1TSX|qE-XCow ztlf)MwH5*IdS86WYpH;@vQatsmJ+FdC{3;ZHkjCX~O2zWz?M5%yZce$e(s087 zZ!XyxWFQ4jm_gF&oGS|WKtmv?GJfamaDio7JDLHRLW2;!_83R@fRTdw)||@pJXW=> z;IlEvL6l&(+U;Z9;9>%%|1j{mcLJ7T#_Z#AR3><%28~!?frg!5isJ-xxG9ZN!mb<} zqDbO}v0wQ*&^R`0Oh6P{cquLlOM`|Qq{HzFMWWKB9B0vM9(b;I73Cf$oaKY|MC+O< z6jN)qwY}fc@^4kjPG#2j4i zo(9X5Fj|hh42v`IyUz;mQ4o1l{Y-Iy6mhW}CXNzL`C1J=K*OhuqIan5Qc2V_)R6p0 z=?0A96!u&nDtqsZnj(bPZb(cTWR=ttqr7N42lMr{AVB6aKw9&X*$!C&`5zTzxHIkM zzeQ^C3djmkJwBz%zSnh9zW%T3Yt`2*%kJfHgFE4~|H_h=W*q?tviA^zwZG7uT|o8T zy^mSF{p&A1z@PHA1ZQ-^{bHxk*FW319+|uryUFxUWl||3i-%*oR93Mw!NzSRo=^>- z7RjEZ0C9tZVf{l`X~l4dpvV9eB{$6Fw%@D5i~J!<&`g0>4Z} z2r@ABxlXT)1-gIIBv}m0{2Iah<;-^QK`1SVb`-z{Eb%j&*>)~nl)&Xo$iR<5(s%#; zDlNhE76#f~O|Q+Uk<}7Oeo>1U%c)h=)TzH70V_v?zKvuoMEWK8@KhItBEU-$fdHDu ztSr(C5AK0IE)BrqKvpNr55H+CC1pak!*>yUyoSJ>v-V*_0$VzB+ zU@0vstj+BZWk*-yG)MO&9vc221M+{$tY2-3KngF5Xp|@XX4cq;S?3@Nvi}fQj}R#N z1XC+mMIc#9kC$8)Febqag>dS7bBbt<;@xZ{&L`yn5+ly{3bKFWRqyN8tJ1X7GU-LYKk+lu(;ujMlx-T7PYfNehk@aZ1bBcYiSa0y zMK@{!!7`{c%}+%=IJK#TRj9>A$<94?S6wVR$*a)Xi8uhLhSd$yaW&g)D9MVj++K*) z6>*m5%cu2?sEBurBSk2`FbEYQc7@i5b*P`GW}G85I>J1O8WV89d)|E4lV|XVfc!7k zqmYPY`TU%^T34B$j)>@9CQB``O|>PbI#;Fb4DCA&7#`xtu?v|(4+ByL}$tl{ScBASplC4KwzOM4S1KjQ9bD+(6wQU zOj<5}@U)^?&VTUgbC0nHC*a3VbCk)eD&fOJN|z9PTx(r^gj8)h!+1k%7Pu70-S1J; z6Tf^uu4c?798q#fFl+YuXfTciC#7^UzqkL6**-&aT&B93OLtHiovw$G~ZBbPg@-x4&KRuDBwY3vTL&3z3J5@~ zah@Cqa&Y7EpzKafmqQ{0l*H--5&(i!wh*Ru_^+SDbA;_N_7Zd{_^BTU08k2F>pv_1 zZOmj;U}}_5GA=Rz!5Mo(cqF%Lyi<>s1Q5D(-mH|V#4|)|0Xf3^R8^1SmVcbz4&+z2 zsE$?Kua#TQzN+EvwGd3QXc1nF|HYO5K zaQahLG{=9se}W>FOYYEKZ7)k_O>4+F#x4o=vS$(f1CPN|2OKvjA8Ljp<^OtCgw=ye zijca9wQ8r@mr!u13|K*s(#$MJlFzF)Uy{r6wim&`i-9nvL#Zpd51v1;pcws;!)7e-{2#F zmt*xI4L1aTHq?n}1R7N89(2woQnU!F%SU5w=D@QvTzYu@7W~5o04QRX>iyTwuHB6m zc95xoqgC8@6$x=~>3<1(UA-deN%Irw}!;9XbuEF-N z`SHATu>d5q1*fUhSlO2F@;NOss@K6)=x6yl)VsP zSZ^&rSIF+KQ7mfrPNRxEMzyjtPAr}yMFm%#*g{+FS!vAYo=Zam^;y=C^wdYgDRLPG zT8D-S7u9qW;F`TA_4j|Y;14|2B^7}~l^9uY8mSz%o1*bQSS6r(y3INrTZXyvD#`fS zt0+AR`i?Hx7IS}qf(4pcT9guo0dzA0H@?t#PzfwcX26|CzRYve{~@=PUG}CJd##$H zj~6N2B0aHmgl7@$7jzGAq(Vp&i1E}_lesOs}hesn(GX&uy}M24L!pfimM3hkZw&=QkrOsqZN}-et2MbwU>!t`o9{v zoLv&y4EgVxf?Z(I4>1*UL7gn`o{wFN-&B($9PeKOCfM*mfXR$i`<3gFt^{SC@Tad| zHNPvvLAW&SDCzlVn^){#Dxl#L&>%IGgR>(#`$1-$R#pRI9!y|_-c2WSUifK0-2%Gb zek;mXt&sf17IsFC{Fw1RJ`sHj^mayO97h>g^-n;oT(&wrhzT5BVEi%HEjNPtYHj?C zt8c!_)f!ulGmqo4Ttj!HD?jL$~gv%L#Dkwca;2ijGD7{weZ!o5}LcJf4-6tv6i|KczP( zcN`cKbH)XxXz_$mf8Pm(PkXCwlXZxE?9dXobI>N74V~bBuNbbBKp-0i=l<~o$=WQP z-pe*;hr0@uf)PLK*5)Z$R+MM1!Yyq0^eS_tfs~D@Ap|V?wLmMkvnEE$0LeN>7_!g} zlguAGOhDHx@PMKM8RMtnqFl!_?3LVFauK0R>>s?<_3zw&mIEoY6+WxClrobb$;qmK zXxLWIO}e$g@QT&b6-^31%p5kn(@%G6$Z9n_>%ok$ZanUy#99V1_+d-|9I1t2yCi3eFs0+Q1$^y5x- zvR*7PY9jOBY01183Q0xMW9#P%l0mFbZ*7e2=mAg=&=gzQ`kN83pad)$T$LrGoXEy) zW{Tq*W(fo%0)Y}`Tspd(mGD93B3O6v^c|R}*7xcDVG0A~5@Zq&2e`0~_b%-)JtM5y zvm<`0TXl6siVTk{6sCT~_kGd|V4kbVVF-DVS0kYW2$n?HCQ$bCIC~FLszSbFn(HNH zaiIY)OTlBDyREg!u?a4N84SWTH&(1chdpw}LLQcf0D(saBoeuPTc2w4K1XD8ff3MX z)vz9s*AX}!;bID)^rL!0`U)h3}pyra0u#;IbDfkt?g+SoVD^{)7Q9i68H{JfTT3jJHF=~agD z;g0;g&&?D*)3ZU2{3kX@@n^7X4Jxuzy@$v(#?Or}8fvtEj>AcgB`_=90F;6exV*JC ztgZ!H%O@T<7mWz`rrEB{AR^pzG|4%TN0o2T10P^Gn0X}7a zV+Qe{A#&IHFi_8`ywk|WWdV_cagVU2sCMXkO4hl6eKo3tN&;AZleJ9N(qHt?OW3?; zi#akNJVT5OlH}#Cqyr!!jg#(~M`rd*5r75LkOM&dWu1GSmuAw8r?@jG3nNpu3E{BH zVSoM|^O;Ao7_njN7DM6bu}3-iLd#1wemLDpgLDP)`7sLKwZ+JRFEtnrQBH(QCX}W! zp=<5u6tZ*?Ds+080-5p^&Jc8zXws;L?}#w%3p#!TC% z3~?Jh^S?i-fBe=tsgA*L$U6e5G@<+e(0jS(;cW)c?b*BUJ;BZ5*I@W zB>L4k-ffNn59?9g-OS=!2;(BgKg6sFKN3olPTSXR(oO(?7emq;o66ZL-JUOPEJZy? za{aQHu}4+6TFi{28=7Lda!k4`0MG%M%=;OEm{I=CgXf!*%^bL%-=Pl643PWU(YD6T zbGy^{NsCGPMA%2@Nukkg8s33DOLIOL6?g~+G!QA;8%~(rZL>lch$)W4ilzT*{mqQa zhoBo9NIlQQPK8sDtFZ{K5UgsC?YR492iGG)syILlj8f`el!f?#Vnj+C z`w$-Cwh}Wo?(}4o38*1|d0b4Y-v zQTMDsQ$n&fy84$KT$V3lRF!i!cL|07^Eio6uZKzdamdYNo)1PO6}r{8ZDdGT;9nd( z!s`?4grx9u4Yq889*gi@B_`|DCJ0zOcmVxJS80Rigqk?rhh*fMs3td=-jZ~X=)y%m zh1)*}xYv~^eu^k_D@j}aGdKpslV;;pYP-ZJJ4`VQUoS&>& zq@KWY_~hg?2WvA~tnpr!0%3l_)-3bHNyHBwVV~ zX-?)U=AUP@kN-_Zq_KWEQF|4IXX-hyN96feH=!iCv&>e0PAyyY2a7L-d*OoBu4TK9 zbWe$+nClM5G8DbaLA#wE2}oiYZtlU;DE#$Ae91 z=twKE>Sa(|LOI_^hzizGRcggQ#+`yGVSVkVrjn5SmidK+h54>LOalZ-o#TZp12J7W z(Cp|S*~c&7&(5_f>kJ&^mQo+wzoWe(0M6*3Js9xK$56w~bc1F!PQ&bQj$GT<&fR`0 z*kZ(W4m3Qoxo};kybBQYF(|NyY5EWlYy7+u1t&?!T5= z7P{Je+Pb{8#?jzbr)PJcUJ|FjZf(z&YFK1h{I-Y?;$L-1p%sHJ9GTIP(n;X^Q@moN z!fFQr064Eh>|+xCEzBo;UbU^V4KK&E6$E2Uz|z@SX-!9ysX{+ znNn&UVTsLhR*qYbSe*2ZknRSZZ1mb9Y5vOIIP^_a|{wz@cG`_c^x)igmDKEkZk-^lBWA?9`&I6F=gJ%#` zW@MH{WqMGvj%24dkpia$L?xtb?r5Nx5VS~!U2T%1Nvz=j*0La3+(Fg%bd`Bu{J8}R z(g=s=UUvI%USV+)Z>LLFr$113ls5H*o`>q?eiy2-F~J&kEH5^z1I!Skbv zc6SB620=D(3d*)NXB1vj)Dt-(*={vpKtdLWf`h3H7)WfgBuSA+Cw~{`Vk~ZM_(~He z@Fwp`oPJxEYHIGIB5XjQ#6ZVI??Vie!!Y0PIMurhkIN=WP*x}xX{KUm!sT62K`}$t zXQZNU@e-QSZ(v~AwSR`v5eNp<>WAp{)FW_EaMr!EJEsV0mXxejV+iV0Bf$6-Mx5FJ zK~h8Fmxp)!WQ7qRZXp%`z|ATs3v(Ugp_gNjjTbBCJP@#PP-6o^BCXU7RO&dUncVUg z3H(GYn3RTkw6>$%4?SnKsk>Y`ef-{#29ofY3g4QhRcvU2 z$bCD^EY-Lhtr9^EVO2I-6>7Few7`_~2x(iCYFH0FX=a;B0310WsqQ%M(3R)MLIf~W z7nFF!vU>Mxm4N>g9pTIYB6cKqLvUMFw2%4TuVYoA13m zKQ*m`oz>KXZf`b7{IFMM4Mt0Q7_FKT7ZHuqsha%GGwHp$y1s^5`^gSAul=VIDi7QL z#wq;R=|r2U$udrruTXn0@m>ZG2ry>;bx;>U$tB;mhRzwBB959IDC?2f9@$ntsXJ?L^2BY~vo5O;A z8sMcPk=Y@n(OlZZfAOzK#KuIH(UKmo-csTcb8qa2(7K&g51< zN5(NW@f02gq+#(SEEg>0##CE{^NP?rlDOdA5j705u5^?HhC_3>T-`8v37 zikCg?qR|ZB+uo%V3a9EM1;e@y$5j}U!s`#^GG>yt(I)pM5=&6|p4(9)E2)E;Pw z@20>GwpCl}wRW6-eyQKEl&L`gTEX3JiE>c?h_A8?pMa9z$$T;k$~4Dxr6b?@LJ@(v zdFdxRSJx(Qr*hA|++z6jsZ(_TBzcNz_RSeBUr#mY*xU5qj5}%#bD_K}k4m4C2B5G; zTs{9iO#g!TM4kgci>jc!+Q=71!*S;JF|U;! zGb+~KdS?+U{n$SXt1g}us9Blrvd9ZC?vj^nzgC=iu)<%c41 zDcI_LQ0g);>~OaN_V3kJ3hto5ktz>gj0L&&9`>bhGD^6^eJpCmIxBANvEHksd8cLj zYQ&%M+nr*~sY8!Xad2Rh2YtX%J?lhXk0X=ajm+&6m8`#RNU9i<2OZ^)=}(qS3T-?c zfz~`_$kooYcZK|PZFQiMtrlRILE^uLAO8;J@K27PnxmBI?wO2N6{j<>;If{9zce2ay@we0<9P_dKzw-k{j%u~NBV^|91ir$HWe6Tv;Wr48BLG_OgB$BV z$ockqU-Q%IGTbdQ5Onw8xBn(QZ?ygz^TU{KmXVwyq&QIi5}?MmgIqYWBS1iPJ#*vQ z(>pCrcnbqc0a=H2B9yVJq#z&_989cK8B;;K6=%CP0S}?i;qdVA%W8G(x3EWz0nX)a z%=vx%O8S)jryTaDcn)89ra+&}nk)a|0aH^kV&p9wN{yF;AYe+B05F+%N1a-J$yh{V z>aw_(aR*ZaD8yQoQj`&lKUeON?kCVt8%uaU`GkINq@%lz8#g332z3Wz0F(HBb^Jg2 zb#UG#O}P4c;sX{^z%V;^=y<7^siC3&vxiOE4XXReZ6ZTwZ)lw0^Lb*(Z7fP}m>QZ4 zVuoDZFFVx*0X^B9>4NgIEljH79M`5MR5Vtcl#)9>quGJNm(!Z9u-$leMM{XB~xWR zFfsq1t)|CdDtoH4izdO*yfGf&@gB7y+e!!|3R=o85&{K)0SMFu1R#dkoIRf6k~)71GY=P_L_k~#L>)6R z*iUUJc&yfiJP&L{|456kl?_^k`b+@zDYK)%eIq#K%5LCe1kGG{NMDhDCM910PxUv% z0<0UNc-vZ2y$^2LlMHj-^w$e`hxJ7%bVoex+G8qQ)e6sb5iqW;z(Snl=f@s4FC{uiV_Vuu4o$rEz?lXlu~8g@D4%2OKX3hrBV zq5WX{yntZK_h-_9N(PL1H49c-&dxfIv_Q<0MMcML(*qZ%#2Ll05p@m0HWa&bo?UlQ z^4qJj{nLb11Aa=-yyFv&=yoqd|!sE5HPJe9o zc5)x&fB)e}K^XO53-gYkF1=sEf*W=N@t5H!7J$9L%amAVe3KJY9;;N9^A2>nmI+C zb7fl4y2h~IBxqjxla<9bnWY*?&N+AXC*jqWtFowSSBJjbHx$~Gm{Dsui0LL6t5p%f z69H9ohXnYcydRH&<2pNorjPB8{ACd~wUmbw4u%p*Jxs`DaN3xSL;Uz6il`G|<^BZh zb4hZ5=UoO%EMMxo#fR-Ku-q0$9OJ4dHsvA=+KvF&t4@tbaQ;;C&6eVJRmI|g2Y%9e z>noltZ5&yDLb7UnEVf87%dbiP2_5P7pb(8<50YyDbl^LAedH>x?^}6N@te8cb$qRY zQqP5pVj^54y|kV^N|UY$l@RXsih~2Otc1j5D5NXCBUwb2F1NOV+4RY@Aq0{Ry@&=t zG<>t``JX1qk6QC#T?h!O#Q%7T zQ!|oT5Td-|`;iiu1HcQrB+LZg3TqGp^)UiS`S_nmPo{^Z!aA0&Z@i_UXrf|tfPzdm zN);+Q2=dE;JaYuhBQQK#MF0ocH08&+7)gnGR7M^1$gDdMlLie3Ssixa@BuhCs2D)r zbR$TzCR6|i@N4VvDhU-PJ>#3_gafpEI~c?cWu?DYxE1L%=zMtpH~lK8aRH9uoCFQV zMD##}Y|!L3uSLCoH-vsvp5%Z~v%LTU2>Xu;0*eVVdcfS3ih|`!DlQezhY|! zZqjMH^d((Mk0IzQV0AOm-f9Gh_yM=~Uve03=WUo4?Vj003RA1MqFUM-=9J&N|J3-b z{O#jf0yz(=V0($uyb-A3u9PE)Nko0ohHrnvYnDo&jrB){GYKFWx1Ld^Ol~E%&m3HI zWpJ2Lx^xsucK_wnTKa)K$oIob3p>99_zsPFER0EkTUzzzH@AGHEf^O@KDm275myJCNOfUCMbT@OEbrF*^=Q%LJN>MVyv5bYiTU9 z@z?v)eduBi=U>24*71q^i~j-DDB+nk;k>-9fJn05)A04T;Z{<=(F`1bqJV}62CAy4 zzlY7tHyV53SXjEd2mI9S^SZABL7w?u0?WDje=^6iS>0@&m2x;z`6nMTUU%i~IjU=)QT$0}~6g&Nsw2$qK{9n~} z8+CEx!(aL8?eh}M8n>OmT~illaN!rQ_|+iAXUahlJmsj@_m39t-RBq{o#34hQIuDIPH#>rjfGvQ2K>JWuRHEWf0^6bxqO1|Om1#nlJ5&%@NXFX zd#n(j=)Krmz7YueKq@#p#-FTuX|F?=)LRR0YY;Sn>scAqqlS5mZOAVp2lk}*|7Ckn zr`yiAHbnj>9Z6kIuK`vs+!kfwWfOi*DO{`78-&pQ=CO9HYE_RkChqkr%-}xq@<^pm z8V4uog9{{#^!PHA(8tzHYSTGj03L~kE8bWWwd0CzXWs&zP){k7G%SoRetb@pT%3@cu1A` zG?cM&2c^bFxA@ur-&9)JhrSH}qeZrHa`m33Rm+lA|4>SkVZgZzij}3?HbK`kDo8si9d_?x19$} z48;fl%EGv(i*9znlDZ`Y+f+}N^tdWcO$b0^Iz; zn?^0HrTzw`V1JCQ?Wy^h_sX?1-}h;}!MoF?8aT+%^U3!2`PZ|zzgNGmZ&^fYNoV53 z7zLYK{e?B_TLnr=Zkuj=?^=pIB=*IPx5M|gf(Mr@3b!Tt|8;(O+?x2lz3T92`umJrjA3rr3DgBp=s_Ht} zYp-x^SINA>Y1#G9G;vJK$M_U}Z>ph9B(hgtlt^to8UuhJ_piVdLRSXME%~nCk>drV9;IA1C80mCB?dgQf<^r9Uc5SAe?LMQh z-RTOp-!0e5UZI{c zxHhL?Z-~XlMWIncgC7sDO}$APf`cv_$<6ARifFpNP^LJVInng+9#-5u$=GC9m z`M?0o1pasYoU<_j|V`eY3l?s6%n_HG@gg?Q=~{IZEf| zUdXPP`+?BK?$*7yBQ$dO^b2LbZHFLktov8bCKhy%az3NZS?i%Xna0;j+x2OeBELR~ zkPUPG0xavp5LBxRz4j8*7ZW@k7J(o^Xuz{i94~U*qvG19>5qvHxCGP%-D|MI3DYC3CMJ-`Au*DiZ@ZXb)cl1*7vT(Ztv#q19I*F@8&N;n+NxPwfzvB!gsk`6-5vOfy{0rFWzMs zw`ud$h?@GjH#(3-`X?bb9*T(shYQj|Z=Q(c$BbMYcK&~jYCZbhZ-l8Q9Lu5 z0m_`~DIv82?k3uAa7w>0nJWLV`-wr@A?MWZ1LO8?*xBD_D$un9exQ4UgYKrts*Pq5 z#O>;&~}NQw%}DUR|@h$ zQ=xrLHOmXE4Uyjl1v}uO>bF`CeuD*(xVYPQx{|fcv&(`qRJSHrfD;x70e}~H;KrYD zKmic~kosVr5kS#3cipM_bbu>`-*f+O*G7SjqWin%!L4G@*%FlCeRyaocW3L=^J3rX zxB1zJ5J}wRJ$pj;ylzii)O7Fue)P*mD5sApEq|mMnE{eR`lKF78-nW}+MxIo1oMw7ZG-D_-b$!aTx1M?^oezcdJdmh`*QOM zE|ct`8o=cfXkjVR6so5=RF8;DlR}O5DpB|_=}WG}isVI7r9!YI{FxykW;Y2Lu&v5T z*WS;Dg&>1b0OGD)dJIvvVVg0Xi_w&U90zH?ws1De1E)kl zL>}0FiII$=X&7gb$^uN1IATCo)@URX{{;g3NIogu1|vDcQrVNqy+FBbMk}PBap9>o zcH@9M9w`LC0*N?)d${nvX%^Ht&jNYt>nHn(m-W_n+VS2uUcLVuy{Ll=w1tK0G=YJF z(g-+{4ek^|z4>ly|!1_twCE<8|#=%?fjY6&>$Y%^f|^q?9DJV6&mU zZrXrQbbBA`CvDv9yu~)m(9)0GFw1<59pezfu*9JFlKdD-1i#V5#Q?H&ROXA&!;i8* z?)TP}bpPQT96w-aO|UC^ym%fRGIRBF`>8xW8BrR&I{uJRyM5~86`HXG_|XuVk;fb+ zWx$Es;R}&=+B?zj=GijVj^b-xp9)4^FZDn13M_|o*NW8>|IjUJZ2jaCKGN>usz}ve zjSi7R>A4^D;+VN=vCi0zSk~J&pt+Xt$K$tZ`c2~Rp>zK-8Opg&{+muH;*iTha0)yc zdJdDmTN=C0%_oOI#inew;In0fgmKw_h)Y@Nqb+_nD5y%dbP@F)$3{e6!h*p|*6Wdz z*xJQ1w2aK;sR`5{?Fv*a-vRDnn09$4I*DqByByDE)So{1#4ePtEY*r8J2EecAWGyl zpb-i19LdcT0_I?xCI4WlSwi;(3GBgvq~;gQaSNaPxA?8Coq!y$`m={viAz91XxIA> zCQbM5)ILS$JARShb3%-uIq2qYD!MSk$F*QH=6EeJcVmrTSL|AsNLS1>i+5Sc zAG_AQJzxRLmQUaf6YHs?ZF!5V7lHeD%*{&}K-H|&OvhcHXoR5EPQ z;}89)Q%X}7IN0}~H%y`a&Y#@pCfA^A`975@MHV(|1`Z2DK0WbYFh&~&5gm-|`fJw@ z9gza4%(-|qR)=>?KUb@CtCQ_;DUUxfg1$CHOz==mz<`0tPtPF$*O4ZHt?z96$x44Dg3)TAdiiGD_OCCpiN zL$2mr1vTQC6CsTOlM?%f;5TDQuH-HV9_gprwdw{Gqv{NDy!l`@z!tU##>nmBHBL+~ z&+H{x6a4IsgmWy}Pz7fz|L>tc6Tay;2&bXMBClAf#)YNfT&8JT_aDju$e)=AlVX6G z!ED!Axd);>yi5o+8iH(d5J>QeyQFR8I{P=4(+VKz@cX+^ZAc3conRyVrMicgy^2o5 z$M7_=fACCa&knO}DKD2-GY|IlNheL!(A;bfeAAPAkEt|H&WQl^l7cV)9Ik)cO5TVY zc;8>0)`EiYs)i=$jT2G#M%QnPzg4fVJi2`j>&BD|>|G-~>$v?E^*8qI zr#)=2$HxMT|0M*yj^XyXe+D8Fkh|^Czc<=-6lD;?vN!KuyJ4{-TvForj8Q=PmYL=fRHH%@@-v@_WBj{q6;Wvx3I=dG~>Totu}pBfP`YQ#Fn-sTvy4 zy(eJ4=e%d(<=o`=(E7#nHJg86=RnAyp5QhchR0CYwxOYMf7f4U58rROQA=G0ZvPd( zP)97;As5jK=Hh=ovSRyfj|P6i(Q9Ie1-o3aLubwSECX$31pAU03qU(KPVhukSUFas z&fZe6U(;cMp;DA}!6SaheqVj=Up}rW$Dg%Q5b#!YY%c!ExGzn)sktIG@_8u8Z+J3MnAcI$vK;HvrIh6cKicFfOCorB@9RITsFO1WQ2DT^h zUJsP?WaiD!6?w0d6bC74)yqaiH?#$_mURkQbwb($XKHOpgYCm-SZTPgemWDr;;Z~4 z=jv^#Kj>`GOmmoz5oATMru&=x$me5xR4?%vo3X?k3Fu#n`OnuWZkiQQr`FU}9$kAR zMZ@qyNpf&tAs_wU7;o^1P}DER%3jl6Q!Ce?j~%( zmQ%2dr=wjD=6?w_hMk@2w zJ*6%A-&`&qTv^(urmes)H~`{~cwPfk&o1KfLO@7x$A0&+Qyd=P+_7P_ec>ChA!2eJ zC)7%D!+#X;{$5SJbMqXq(xesV)3$vVAW+cJSiCa7J*)5F72N+B;e*}eUjvNPewPQ0 z$?pP~9bA$veSO8xR}L=4b6|a+-*7Tvvc45=WNL@|$ZNz9hdL zLj-Y+=qny<W&o`KTNaU|pZUhJwv25bloYsIS!du$=E;u@4C9D|f2B`)B z0>69{|JNM}g6J=^QcR>UBMo^L?Nc>iuKWxD6U}vjnp}$EA(FXFLVdG+7YqD^xavc8!=-Mv`9K*t#8WC4vgg$9;>t3)l6LP%CN+CH^Po%^}uA691>4w9kEYR@)-DkbKn4~LVi@#=t~#y+*E!wTsq>>`%0u6lRUWG z9}ZDG$U=QcKyZ30>6!bfeT(k#jHLs2E<429*3v8d8#J@^c(nEV@fXd%5ky6Vb?_NX zp*l5vv+O|0xRmC0`RO!&>df?dUfadq{tUxYw^rf0v|iwEZrDrPAOA8$uiwu@3*v?O zJpTOJeK6u+uqs+M8%kkeEHn3m)hWYeLI1SEB!Q^mm7WN0&N1F1O=NvY?ZihZ;(~<- zkfc*L_|-~DdaTV@6%Vg`Z!64UEXw=^Ah6SMjwBgD3%PdH!=L!DHw(};Zk}vnspE-lF$tb7Eg`U)HA7T zdy#>Y96>^VshBgg7sz*fMxy}jQ6rIJ(wEpQ-RQJ-c5f{i67n;*PDJN1izy=7@^WVh z$m-@`{yB=Y_6KOBH}{T{Hus*m&Y-?WI1yeM-48zdNyn3O`HT9YT=^imoO3wzWu+*k z{Lo1H4uJ|eUiviL31lcA40jOiAw)R@~}f58g6sk@g181uD&0b2tFnlSHaK^Lt- z^&yxxz_KeUEVvV6akf6Joz_}3o6a&4%RRx_KV!1!i*{QtwCk}5>X&ZB^$ml>;DRE?or7OaJ$?U(SC0*XLb-d$h*;e7thNq^Hv29 zx>iN?KKtsb@)$)Un8Coj`7Ltl#0|H>$xXq9-eFNzj#Ar#={t0Pgu&o7)IS^%pqL6h z2p2}NJ{psdseK$!at-~!yqmkeI4T2`eLVkB6-!gHX-78A%rH%Jd^G;Rdt9KcglpY3 zS^u^Pl~15sGTQBt_@FkkINSE`7ZrM_DG3o;iO>)ZOAqUOR=ebqd5t3y#YDkr6~5hw zL&f?%{L%X_xZ6y_p?cuQcJ!h|a_)5V z9vp4<=eH30^?bSr_?R5rDn)PhU6UpUI@N@C%$#kf3Ko?kIGfc}qb?=wvlwXc8pWda z%+{_To*R_XA~jo6%f}HT_2}O;TJ;)z34ofam_cPH6%7&FqB4XTq{+v0!r0cU zD_HJ6#xChLI{2l3@Gd+zc`aV>PI>fG-a-t+8$c1>v7o~mGPsokv2j=uM+cc@`*v-v zcDd|buqo`oVwHBGs38U8*=LR*r)I62LNf(jkkmL0N=ODl$_KI(R_LJGN`~0aAX_dU zl3!kD6B+cK(LINxc9ddYXfKc&<#SB6HlHl;x^x#t>r78~d6`uUzoM-|c-;CNt0-v! z&oFFMMy+Vs7Fh&=IHqEgr{_GLuo$|3aTsMMU;$l1q^L|IosAnZMg$;p&Fci;@Il`) z&`9HoNLjpWW8Rnm7-X@mz?kF&@Z!Ht$2IR*C#SBpn)Xqv4np?%s&*s$NB~~tlwUdc znGB;DD^{iG;Y#hA5(D56bfiBbETvL3!Oy>*R%JglI!_kYr8c5P$-D~&!ZH@-df_93 zs|aPnv;$$kwo<*v!A88~%Ec(hferpzU13QT8XKY^A#$q=%xHhp&-!9b4^LC{%{sl| zUn8j$AegZUleFNc^&jbj{p=(991MCG3->oz2+lCHeS;FPTn&P$Wp|>Hsi%*jP2g6Y zlZsG`YWBA$FHQ035znzehlTW=4^9E#Y;&J0k__t6`rXp(u9qO|@k4oqYiuB`{L2X{ z8J)jT4w26&9^dfnPtq2+iKlLFgJ%%r$AFpc+@s;YU-WJ&cekJb;$UJ(COfHxHG9Rp#U{0O8T#wo(DJvf9w3 zJ7PEB`ZwxdBge~wC_57Nm2_iJNO>+db{^C6H9i#_<_OZD`e6NoPPQm1a2mmkK<9xW zQ-_~3;TCx{&Fu8YDXj?3iapVRSy+g4Th&o_zQY7jl zfY8oL%4p-OoCD1u;wNU`nfLEZ3{^HoEuT)pq|lN%WluIt+o)cc70A}X2>Ob=x*c0H zD0isD-me)~$^HnE`&F7sxB#appSz)?((!MEyjJ~8IvX*ksK&DLj_%KXyMmuTyCPpv zY_>Z~_lhw+pJg6PSnpYx+gy;d`+Vn?6GawvRz32=*KbjghYs00CNxOo`dlYxo9J}R z@=YF=8iywrUNCpK`Bi6uSIpD>&bjYs^6W zU}#^iOB1Qbe*cyr=Gx;D6$Hc~N@{bg$H!tO=s8L&@S+lq-|(R0li2oAQ%nq9-x|U= zYSc%z1K$Mf>dS*UzwiFh)<3!0d#_z-yN{tK{9-P)x7L666YT!!wVlRij zAtQchf=Vn)wfYj2qr(K+GRs}^k!q{~V*o@j5GPcC+z9JKY^STg3h|J>ea(Rah*B;z zNMUgJ9hS$t=nw;UIav}&GyaR|&E1nK%-^Dm{?-Tp3i=oY^xh;unr7-SbDA!S@H_HXpEWIc|lG`0qXX1Ee}0*l z`75U8SM(d|BX4NrbDxNtW4{@n$pzqf5_yHQ7+n=13_O@Lsm?^cic`g*}I~&SgI;3icEldC;FG0+fCqU|rA#;Baw}yJZO((D1 zQ0V0Sn{`BsXQZ|nLaZ9OB0Vw*&T3lCDM}gNN>Op~XL>N~-g)R(@~nk{SB76=WZle{ zo=b+O)@)w5W{Z;1iPp@#KU$2bH(_hf-t0}5DDmo0V;ktqQjgPn`u|((VZsLO0aGeAJfXP z;E5vj#KH+RvfgMSw4up~M#lW;RZP+0#+ z5b|njc{gJLlRg_I>js^5e8k-S6AMXKtwIF7|HjyoYn|F5jQEA^8`ftin>N)dyKI)S zn>*8)t9G_GM8lU-JH9skZ=^l3JG&gUg9dfE$dUCAL3jvRJ}|KM4hR2y z0G1Xt4K=k)3)rHPjDZ-lJ!iI`2ZLe~rY`&Dra1lbP=vtsN~9sTIQxu#_g6byOy$ zcf<D~|UIG?h<2*AfFNH#C`Ur$qi$CFJ_ z9_nM`{*TVVzsG6ZF5>9czKj<9wjVM7Vs_?3C&qI|-jVbaJ52!mC?o+6DNl=DHM{s# zxj$;he^fPDv07GFrbFlc!lL=H8?lHnJceNKBZ32+@U7elUB+aA)(dboMx2sSv|(-+1TN@X16uXDpkVsHaZV93NZrlQSUJ>t{4lbT0$1)vD||jO42Q zR}jR#aD;RWqKk{rM0qwpTPM6oC-uSwNBpxv1^l%#j+iq$RG>w=M}5inWU+??TA^&ug-Q;h&q6<6rF?Qn+&}1KLd*L26bF-4r|zq`pvy0*`x)_6O~2P zxF^o=e>W$uuWLK=XG3SJtD7W(qpXToUjT@f*j4!*<4uB{@3WL%R!u_h}kp?Tqxf5TLA)OssGY2JzY0FSqb3W(r2RVXR6jH49TgN zuV;|Y>@BxuxTOSu-yduM$#2qj0`(ujsuR}U&_n4|fDcvC1avXQ!EKSjl$b|N1ufNa z6O#&$5$Vm)K1DEMI@(%Qy=0{+$&_l1mq@kPk^_`qDqR6!^Q3X)aaKSSY69m3E|ly7 zUIZ`gS1+Q&wwcua!>bvmYm89P>sFd!&tC1(HgW;|%%;hMg@|r=FOT|PDS)9AXIBY@ zo8!^l7TkJ<$vExfbgKVevi7x>@x&9c$8I|^3)erq6qQXPt12=~0g@r7mkIkN+qczk z5r2*U{aJR`;MmvKpKLib(H~;_lfCB=XljewTIoUHfyY7k<))OJ;sZtLP*7N#I1hAY zwykY5ql;k>hBJUK#i>C;(-J(6#1S7dZ#t2{KPrvoOk(2jN72hH0R=AhUd~(OLTJu3 zbLCN#=tEj;2a^o%;Z05UgEWgx19eIM-8oqHTM#9H)hUG|i)lDnEFtl1AxSp^=^6Js5_ za=2l&H{*lUmko<`)lb*6a^~CRtdA%zWP1dzX%~D9fF)aMn*)P*+(|<|&Z6VX$5v4) zfYm+^OMHUdXml@gGNGGj%93@sH0bY+`dkT9Dn@~nkFjr87=U9NjW;IdC6mG@tzr4i z>zm`vXtaE~JOGBw!_okUMJX&bXSwD+OgF}razz`1tF2>ET~K6N3o_uC1QkxMmGMQ% zw5VxKb|`qboGO(mFPK#@fWFeWo80w< zxerw*uHV2o_N|lL;+VZ&_7HfNPx`EH?ercv1cg!oEWo(J2n%!A2J=MvYSaplW>!f@ ziLy(#2Pd1zpc*MpGc4>1lygH#(xhP(h?Fh%Q|Are>YrERODp*)(jUFMyZPfir(hah z`a|r&JO40uDipeU2u1c`hsrHJfc%RfxbIuv_qT6_0Eh$>S5ERq@fMA>%%-Bqt`B*(@PktNW`q&WTieh?dkUFnuaDp5k(|(+Bx0SD-M(fv2tox5$Z{@a!m}FL zP@9M;imG5|qj0k^cp%2g`Yl}edR3;kFvNpnekAaR{-h@PDT{WS;ktV4k7k$)x!REQ ztllG%DelH|A{?NO-&dO3DAD<#Zbp@?3Lhk$!PNe&lQ^8Qv8n#iYtVsQ_{5zwjgl=( zdqR4i69MAlcQ8JPM-}?tT!E0b=1k|@nPP+6%pX#^+!@}L+T#iSqHn$VJJ?3D8^bYR z`a-+7Xb{H;w65FkR8Ns5JcnrP{GV|i|J=D^1|#3n46|UhF3wgpa~5O0u%$nxco+78 z$c__9FI&EN+*N#C6hsJs2lW1fu^vM)w)2%67-1Q6{7kkI-J}F`XjJ{{Z1WcCoT3^@ zL;x5&aRJFWC=G+S@Tw~&=fQI+*$u469NQkGG+608;k=v4D1sA=GW&{}J$BIGJ*&SW z6Bk=Ikh3=-t03u1Na?%zqof8c{;Fp)P(2R8cUTVN?)uw6)w2$vH?E~SQ{gy|j)CuD z-HYs#gmBQB(Rrp1n;wia6Bi1J?Khmb^~cozfUo+=s8~BQN=u~IY$Vqr0>|LQXAAi# z-KztNV5co0Y5)M-m6+no>s8Q?k&E!1FaZkAr6^jx;??Ap)RX8ZL$202rdHV)qPvAX zTzD9Q&0vMsAwjkkfOAR)P*jAiBs0Prs8)*1cmY+C^>S<33ielcB@~TGZLnD#S;qH9 zNZ|`7vu?oys*;!xDED0uJkP6QZY&U=oOr>8oc)(#3emImb~q<#q3zYGZdz=Y0YeB) zEuosJJ<3zh;c6wOdbfg(a@zBwsE7F5EZQl3pjU%vL>P*uG>B4xzcJX$fn75_ufUi` zvD2}deT@|z#ZDW=y8cV4*$lKSBP{Lwv&Y7a@Ug>%=wa4CY)k_c{JXAbEwobA^iE?n zs=)AaG%LmR)Lgl)o2ov4<)-T#0>>-BN995jx##h#Q<~$v;1!fbD6jT!%}qx~=iFTtC*{m0sq*0$QbuU$mM{Uw5@WGMZiqZ_0nKlKiM8Qb_N=-%HOQ1{AzA zN&mau`T7UscPVt(0!A68c3dZ;`1$+4q2icrS)ZD|;LjleR`O&9#lLNqu}ixYmzpog zqIj;Kn2a;*#<}rq)mgD6k`nIidqx@Exr{p4NMKC1_A|$pXVwGF7Ta<4jM1O443W`q zkX2(Fi=L32RIKMeooUd{=Z^d&ZyJ_7rk1sqe|*Fq?X5XA%?6Xy3)Eb6>T8DAlq|x5 z0BGlAoS(wpy5Ok{bB4=s!3thQMNyo7@{@E;;z-V>8(EQGI_;eFqkAkXN?TgaXM9;0 z1`}?0TP=$Zd$qrnO}OV{gccp)01V*FRxXqsRFhhghnaYx>ky2zm51CoNa5$% zq4-^CUvaWi68Z?=?GeNxDn#9dqetSm&cTidN~V#eYe*-B1vXlEg1Nv#&9!gwD9a1DW3NmH_4G2b_f> z$*kW)#IodgPjWk(2^(jVO4;QYt^4V%atpVRk|2u;uzp~l1Z|uKgRn6ZqS%Vdfiadg z))ZuG;-5<4vbIL}4oLT*y@I{XP8tm-Q6x051soc>djMui0@srKT(j^udF%(>q$)A= zs?Hrh7NZ5FIlco(QZ=LoZLn3!H2eC#604_QS+T^e_!FD^^qfYd>wT2PtPSJTV1b7W zhI9srw#FP!G^Ek7Afh)AC5<5}K&#@DM7zT}`|))U*TGh?URpv~@iRS?W(NhA!Bas8 zl@Ofy0{8%;093sbCH!1z50E|>QB|Z?u+`2GZN5?A=#ASVKAXtRMP^2Ij)Oe;b@02&_{p(kH=i2yoC3Kx^r43u0+KhATLQJ{~ z^OXhip1Y&{x(NMpWt@vVF&Pc^x&8w$rRyAoX*T29+F@Cx{!241zeP z5|@OhWRmpFBzzucmOpT({f~vTW1eU!l48($y_P65gE!Rs1VtTE`sXi&bB2G#hG!=g zSJ_PRfEXPtuyvAV2Et3zth^Qeoxom`kYAvZ<&=&j*iZFaw)XiuY7-)&7!P?_4*FP* zCTQiJ5*yIWNlScGqoyxXK>Y~*_qj}r*Ea&8$z;GT;!yw3PvtEI=JEVO)X)3PmHX?o zjT+9eCs&sktvnjJo{$Elu6pa!B;&5%S2Rw(Lz>J+;frZpMViQJ$uu|i>rT;{hZ*tH znt}B20E8(t-0cZQ<8X0&c3PL^KN2q#+aNOlQlREzQ-X|-NS_H(ln(+!Qs|ZUGI&t{ zrPt<`V|+j%LRF6Ov`s(ry7gcMAE(77^g(D_{Y05(>(#J<=_jdRCbZq`K&%v7H zY(ZFFcIZ@cRuy&@935b3Jq!a>w+N*grdMYrb}O0c7ha}|Kx;!h&)WIt#^o%JN;scG8@(iDqC56|r7hL90erD}<7;yIcF(t2-R8->$r^Q{% z9x*vh2YKp?+Ph2NJoV~;<>dZVm63uz<}$JXfkUGv4aiArA3yPaZA)jGTcV6Tt;^$L ze3Wa4@XbHawyEv-J&$oWDKz3g`;3%)=zJI(C-63)%L%1`0n|jEsA6Wpu(7ToIbLYiV50i?dsG`dN38>^mc4PROG}O&Ps>357kgh{SC|08t4)nw^%VPkUv> zwS%5i5jRo$)daqL2G->cH=n~MDZdr}sU;k{5-Hrajj=5&HS?i@COUxYX9(IgSp?F? z0m<2>Lde}QINvCi3mwesZJjq5Yo)+*>XwF?^bZa708t2WN_5(e?jM?mCIose5Af<6 ztW4oFT0|;@5kRRt@{G4)p>T>_+cU;X`>Wcdu#&^f^Jl}s$>=HnkkwMcE<OwN0BV5xNJ5B)MUvMVvaD@l4dk6laL$$2w z3IH(&nYL$i*0cDnpX5?BOmi*pj*6wCFu^AP1O3<4W`H}GLbv|@kY(Ey9QJM9R}q8a{G0F9I)@ME zv2{VP%ur61xgqnf1^&K`ONfZ-4D`E(jt7nLz|9q`hbI+^9``)*QdRX0#-{*_~3TDOpdf?obZwqtSxQGVxkDw6LtNo)wW#s+z5 z=u=OHD5H|p_ad(1$X^@i*9|HQBC5D|Bjq0GgmNM3d+b5G-(5kH=--VyBG;0jrO8U#dBW-)#7z#e0-djr(CL~y( zH~Q|6tV)0Rk)Y@uhLk(va}zywm&*B2_1U{Jm|I>qDEhc2Hty%JNj+!mmq9AUJZEib zs{eXVi2f<*ca_T`jl?E8(-1Jz~VvOHeu1|H9w~ReX*I#TC!mjLqv|pp<&lrwFz)xt&1*Yshv##NG_)RXP+K^ zRpdvZcy>}p0m8_g==#tuE)(t|;&zq%vtmtm8#gf7?$QzY>d% zFJxVV_YGE(X?z98ZuNEEi(%~Fv7JWDLHb!3mtg3?hF}3K$I4G8==o&i%p)i0Bj5Hy zO71X|S1qALU2sz1F#FLAvrt=8+9RO3UmmY44aG@1NI^c_lw+xal@f-<>RC3F>JI@@ z?qwi|7F3ms5d;zdo8D7IYPI;nsZ@UMD!^%WpKrIYY`YvZDt*lJ!S1>LWX@qXmN7lD z@ZqMnHgyasw6DO&h$5BUU$-%MT@~7ihzOWRwh9ZUca&B;`A6I$&PXE%Wb5R1%^MQX ziwzfi!BNR$FPqDAE(aj+N1D9i3AV~3`;cPk*aug?O3`Nn|VCNUEP;{gZ!!Y7VE1p z3IixhA7(-HQ#xb}e+94y3KTA8{Or|U&90vg)nas)$v_++kbFh~XD zoLd$Q;t}{2x2WvO_duuOXiijf1dk8y@(Jym4W%z6ylE413&J|Tf;#A)+S?@2(Y{lj ztUf>^S6EEH#axsSC>G5SMD_t1N9K^$aby_URev%ygps70LYPh6wyOaF3;Z}c)AX`B z6GI#7d*6u7+(sm0ZtURvi!Cp8dqQ_(6`I`FB#DbxSe@i4)QX6)y?fY|M5|`rYBT;= z!+HH9=60Py|E-fLb^m>c&hd5e~Z?e;C|vw=D7D3hM((5iq-px2?Lx?sOotDI~KK}`Oy+|5orW=5)$qd8b0haa`^>8b#5h!hJ*p2AFu_d3_vbWY`P=G0)T z1&N`#eqpM$2fLyPMRLvI`PGEfU#eXOMLOfFnO-%GgMdewBpArs-=h;Z0I0$#cm0#$ z$vloQCmsC(YZak>+R8uOl6tQ1`_~kYuakzf!{ya%J~|i!C#o=zYtYy)t%x5cB)+fh zkp0^^gIX=i#?7lXEhWXFtfDk*7-AxgUwY@W+TI9 <8psY#DIOBrO>hFEJ`?o*Fv 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%0D5O?A; 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

W3vhP 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

^X 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�$Ev7^vA}uRJf5(eLtqjbK21Fu1b3F@)y8?hs*Z=ZEEmcw6lY-Z^e4$VD+BCPv(P^ zXOU~;j9V2iO9lr^NFPj+bj#m9b@zu=q}t3B-HaIKdpO)zFGvv0f4S|XZ@((y&jnlr zMLR8mgU2Wd{NZ;TXSRiJ79R;I7qzvyBD5@;j@}Fe7yOcbuQ#5WTJ&p%7YQcdG?6Za zvHF4Pt5FfRascJq2qOsN*3)P zveo#p%BydsaPHblU4M;6{V|w+_x0)$l=Hq{{QiWN$y!^eU;7`#;J-&_B^ajOqB1Ok zp-Fenr(E;6wpag(szw$KBY4+DJ=?eZ%Z2kwBb1zGoj!h7J6U$)?XAN^za&IMEl$Y; z3{6AM%8VA}$&;#fvZnw2nDT+eveRi)pz=>Ve)e}=fQNCDcCx}YrUK@DoyuOB6iHv~ znLMq}`jYS`I3DfmQyld(37ZL^NXl@3^R@pwg>!%@J~G$7MVAk$xrB z~MTzho>;yU0G>ACq5(D_N#}D)(`wfIhm{1?fh6mn#CK;m-EF zE|a}96orWe3sN6$ZmC{@&%N_g{Raf<>RHmdn$AUIC^DO+j{&65Mc9sUbU>*j#(2KkLG$LlMRnDN}mA%kT#w%$14OiLjtD-i{S|mKWYgQp?VSN4jqt1p>u}P4uMlB!clB=m-Ixlv4-nu21t2E_D!y%iTSEhs{9GUAkhq@n8<2T_F@vcDzk}6s~cTArG?4( z;F1U$-{GV6uSljW@aVB;KO-%xDEuC!6M4MZXVRw3em;2#M zYae2hfsyK)mi66_v9@ub5O!un8a|d1O|auTgG#-V!qIeU+4i#7J*R4WQ|SdIX1z*v zlf=i5hd-koNSkI#!!%a@tN1FpOHWms_(fz^wbii=m#Q>eggHZQoewECL)yt;T{swL ziM?Pxr%CSkD$#^BZ}y7f)X8V{SN_0(({K{3V_5Bn9`q|OXf|e!37epMY$el zekz(&qaEq${{4X@f8MvLR8kpzMBMmTl-|cUU+j#S@;>HWhxOwHue0)+MSvA0ef49Z zDON?$=ucO>F}{ZQ40ZF5W#00F%jQ3hA3-#r0Y$0ey&UW{4o;;2K!0?1nW4Egd0g56 zn}JWf7uipY5E>W$hB4!jiZhx0&*irDbvKq96vUm%H;Z$s*|-Pq0u^|+pY)2L$S&rI zTXq`d-^X}NF+FT}v4OSp&p9qHY|@4x&k9ZZYCK&Sr}9UB{=6R~Kgk+y z2ghyZt*`S_s1Mm{)R-47weuV}UYq)mp-QFczpp%5)}{ZW;x73o%}&>~ooZZ;TQ!`c zE!YO61m-xmd}eK=r3zPC-rKFo%Yu=_YM%)PEVsA52LMxFI2&=E>Ymy4&~*@>KeE=t zRTgXS4PY3%9Q-E8gr2W z1kT!f|3jlLa2@lSaN{!DNgw_)Tq8Y4*6(2El5&_4|4y173ioQh%gm*hQ{N7K2Z4^^ zGW}fh)>HRhuY&$oVC}uv4mt1IfEgtmahnrVlj>k7M?|tNpAy1D`?}KA>b=HMUE27w zi2@xLR7o?w_%2*Zv*8Y!IZBo@8q8_!fPdHw3reg$rZeIiGYjQcb^J)w@5u)4U-9qn z*GovVKRW@MpH)C=fB;Qj#-);Ft3CVUrg{Jr1M;qq&_K7ImOf8zRl&nus6Ob(4)|G) znG7Ueuunw3)6RMmf)|B2I?Y1_0TTRI$6QF=g!yCM*Jizfs)*1V~GX;#fq6ez&ewB{zWInk^_BTLyY>i7YG>U z`G*8G?PNzY?x%Q4aT7e0$bLgXIb}HD2IyNFHIfiImy~_PjVYo_)Yc})A^Jij5imU? zkED%bSD~MPiNb|bvKc$JE6u@~YXy9qb-nFyKTqVdk#P|X`b9@v?n4J*qL*& zr+16hyaL=wFOF`8&9EDLyJW3eO<89ZxO4lku*f0Wj%=}fcj|b;`tSgn-;!|{hi?fm zuZz0WG<*-=E#Bb0i7(L1n>Mx~G^>&_%Kzgv^GSLzcep}boyQL~sOt_dNg(Vd(U{Nv z*)<0$LJHY914(SnXYW~%AeY7z$s~FTz5pdz^-~5H4e&v#E@qspnRzYbwds2 zyEKZjxgv!OIKR^N-$WuEU&>`*UPr`2J6@uX>(HJ%3D;RqPE0R;= zxodiBPW(Id;NX|)`J5!Vk#dEhe1`(4%h)uICX8KYO>~?&{#Uzl+e}}0dk%iy)6JU& z%=}`eBG)NWHLpr~Pc?;ovakNUH@2?FTTz>wS6#}V0>7%F(HJDwC9I(ds&%Pej14K~ zso`uap&jCBTX?I~_cC}l{^8`+q!S&vMG67#{@xYLfz@8EEvi2DQLb`5u&OFI4-m|kf7|G7Z+y%J9JSdMPTK5v< z$ti!0f({Em5aLVb;eOh>vq8S$I#7j_x9FpuDUyZx*P_Z8Oa&)ksw~Cf@|+=6U+M~f znn)oNw!wI!yW^;V3zWv_81MdqWQmt5kHQ5rk>_>$pl7Bm{gD8WT~m}f+BX9fDZbq- zd{f4ra+e4xZm96p<6TG+ZqRdA;&Fb-t(K$!K-03RAq+Gi4gs1Ilvxv-nEL%A;+gB= z0fk~lm~q?C%fr=1?Mvv>%Ps?|8P7U7R&Q}cLV|BLAjzbbDoY=}uP>u#Rk7x#8O`8J z{W03<%6ZnB+|&puzF8)cFUg6B-wx%SfVXrrwwq7;R^^BwmEao&|C)2swzrsO&}_kY zaFF!<+@hXK1nkOXN-?ua{sTVsggt9I80V|P@L$;?()^hT!q$5Nv${8RHB-O@2AvpyIS_nfICEo)9DE?!u{{ zUWg*rFPnEHm^Y0_T8nl^NV|Gw#BU4}FWkO7>8b>oZN=|};_HpdQN zEqrelQ>WBPN|DGv0r_};dkBR`D*V(mrKEL$n4R!%qD2E}9G-b+HywPC8>j&WZ>{|n zxl+2_6Y+13AP#*bOucUTIZb@UI5fRU9H@I`(7)PqJ3%#vp%DCCC@e^sE6*?CJn|%k zqG!fDkldV$Q;fY^=DF_X=gl4!d^A1BxM|}T!jR{A5pQ9hsAE6xzLV8=I4CrXXVv#M zH)5pKl>AhdN;z4HgrBmL%tAFm>Y^Fcw`QmmDIR@3v0Tlwj#29XmR~(#Q1kvr$#KLF zQ75x5US4tL*PVX%Cil=kM13482?sT!Dg>?T7EC9re2eGnzwuY*V+uG7Y0urn@(hN5 zgmLs_#?Y_~1^j2jHtn@15|6G>Gdlk#wMUZY>E6nFo@;^yJC8-o(+h_JTzh=%l9=%q z*$CKhY|Z%(U#9|A6RMf9ce{_sUdZ`ffq-4|`pf{MX{UvhAHlY1M~qB5H2{m!!NJ^0 z91+@JGG#;*YwbPQs~E;PZJMjY92>8T!C&2*xB0&S(l9O0tsi@md|(y9!WKlYxeoxT zZI}vD>Lyrh%&4Sjplq5XBqSIgl%#)+$~(*O71wo*P1;OU0A`#Peg?S=(`jr={Ye{2 zlDbG@I9g3lFr_mM6BQ^p(QO?*UhWT-P@|MB311CD+-15)Z6&yB)sXm){Xb6Ejq^#} z`kF)D;gz_K3QnJ{z^) zHAKo1n>q2NJ?{p(Li6);h6uByf|QnX?Ug8dS07gc^O}H7dkeTNHT8{LUPnVP-r!Yn ztx{@gfQ*A+Z~I(bxo7jj8Z^|LG{mrLwJa*W#|)ErE|s99krSJ``T2R5@0e6B**XrG zUJ(-jq8~l)?xw`fc1bOFk-~p1iLHH2Yv#msGhQ>t5$SWgs${xXMIPX`I}1v(ggfGVHC)S$+|+JDob~^}%YG%1Stb0{_bQ6LuBJvWZ}zJ_r4q5kI`KwmRfnHD!6L^Qt`YmM zB!^R3w?liim`e)**C&4|xip!bv;sWKs-8$z8~_x?B!ykTx#~1d6%wRQ|B4)BKxubU7Y^+>;Jp2lfVDbGkE>?gcZ%>$^To%`R@(%?DFY)k9UP+QBHkD zUO@7jN%eVJbXa8}3$zA+vg!vmQKJ_DfJD;KkFF*q*+}!61j>KWl$%7S27odRe!EU} zRWrJoLdik^P_3k<@ITS&2wvxX<^mkYqy_oiZ7EHnWyEgwI7$PNDnYO;bz6}$PmIh~ zIpw57O*P8}&O6lvz}r1Ny?T6ldU}5T@#9In9v}4U@$vCVzr@dv=JiBg&+ww3^I!Jw z=0EBWPtMoKm!E&UBhu5k?|K7>p4~qcJ(2y+gZhuW@bEIliPXs+_3Y>)kYl?;^?nzF zf7ZX5X;$ZY)~{exdSqm5(HFi?=S7a09x8eOGrEV^E!N|q3xobD|L|1&G8d&6(o-5Z%38U|uF+Y-V{g7k(@q?~7XGrb<)s2s@;^=?9w|CQ@6L0C*OMCgk3NG{U zg-MY^zlYbu-QAtOU*fudT%AtlIgd)UaBO9n!C>Y9W<*cY7}IFJ(=O#w;O( zZ8Y=xD&v$DrqqY#bfwHLBhd}5IaBdQ4umrm`p4KV!G?gG!hc!Ap9XE)ij313e6dBg z=HKp({uX}##JczrZNXI~tS;kmgyTc|Z?z|L6E{;awj{P$!)^aOtBpYAdv|YdZ}W0%9H{-`?tk)o|JJ?vFHUITt#aSo```Wg z_wRte{{QCEed%C7xeNc^!N`L#YPW=XrmVeBVqJd)9xuKy--eM~dh{x4PuYtU04UX8 zg#cwA01|6<4H;*->?1+yaiEeSP8R@F9S+N=D28~?mVrk7ZUX>H9R@$IWf#Mm9dmet z4V6e^Q)23GR2!M!Z&Z&7ucRd0mFWsrA!l#;#q5SazVTWDq8AL)pGng+^}5q@g8&dK zZYY2K^H(kT-#Rpp5WbsSmfIoZFTeH$SgF zErQKmc7t^lOj?!^3~PdZp$|?ulg(T!=-XI7j?_vNr`Iz3Q*JYHw zCZM`PS#k`R(dk{G<_EAvB zk1ZqY6(kFrF12}Fn)1|5bBh{HdqMK{s=qhXZ0Srv-4+hKecS0Swm7XLO#MO{KkpQ9 z&8s|EIS}+JN0L?*O9U;gc2#H|ksg1%itbt?RQ~KI9q}T_gt3^0OHmI)5Q4)YeUN2h z!A9d|=4hL!0#vUHAPNAq{>L@t2}!EgWk%Nl0Gqn>r0p%oJ>5g-($B;;XLvgzI2$V4 zi)*bK5o0=LlN2YZa!{X!TCk1v|Mcs>@>MCJy^jBGZ2ZlmZ)|Ak?f*5e!UKN|^lN?K zoc`arz}Q$fHloKMAKUmZT#S7c4QT_fXAu3)`hRg+3(h<6UV7f~uK#4X^eFLlp=MJa z!5nMjr6UgPfBic%*x1nbM;-UYOAT-Epm50l)#u2r!wqrT^^JnHNblxL!(Sh+qdxrt zcL5-EOluMvabgZjw)Zu((dB7+F8visSZNUftl+Q$; z5hRCw`XFlQD^gd3dC6OcdNWeN88V=GY;;1+4m&z2p&w6 zm!!5!)OJR?^SPs`kjScpYS4)QO=ryIhXbEsse^@UosO;>`=0BaTd5@f;n%66I_E6%Nw7gJRzC_#zdzZ7?Le0AZ-|U$tHh|&Ul671!U*2D;w!D zDdmFFkAD2;bU&D?(CwS2v2>k z$!+MTu0LviXmWq0gi0F!>+;iey(iUwpR>nS?@N^~5^ci5FZF|{3$2@D;%jcsi4c*E zzt|)<^*H9{B7#`@C+GKOQ*E!C;RM);nA2l2GgS{JOAJmQrHQ`;!7_bBU5!>(QzwE_ zg)h8pc|A?GQZ&}QFk=By24-F>8&{n&Y36YS7!io<`!iB!kugS zvrN?J%)+BbHV*;$sXj+5Ji&_{7ol|drmuD{Nca#y+eJl7iO&wXv z7Z^RGCsJSW{v2subGft9_%Z#BVj4S8sS^ApbKWWiSCCfdz|z=7XQ@9nSwEnEP6#Jg z#a^R3Kyr5ye{Atr8tB!%%%zt{I|H4e#$M%Wl}K8~?xI|#LQ=zNMvQ+xjg#3qGp2tI z#^!%4GVLLG^C%UA;8{qitlZDYW~0-R`T_^eKvHkXIv=j40qNU|=QBj&>CZly8u?lo zF?i{-ik8g#jGUVE1*)JI*atDS3q;@KJ`4KKaz;xdg~LyCz6LyuT8fp9!7(BlNDE%p z#C2s_1(Y~Wcp8X(B_s+XyN<=FSw;OdH}QWT9{?Jv3JBuo2?c;8v4Uf{@xfKVJ)r1D z05A;?iHYDRiD@g#$lwzl)5(acBmn?L@1sY z(#3&%cEvLJ>O41$n2@JpVO$9 zBmfi;wEmp+&wQ+0(T!370HqKBB-Vd;Vm%INXia>wlqg*Qaq|a?VzB<6{v6#Oa5_)-ZjX+X^Jevxr4 zoN)R$1QnmDz0tHp2R|(@GjZ!jwG1RTa>Q=VCiM%o^dK35e)81hs+N}Of95JKU zY5G$QhhPASBYhrp{4-bNI&yzgz3oT=eOa}@43-OIbcK~lOi^H{51zd!T9CPFP4-q5 z3AV6evhQfwIPLLIigbWqwEMwGMH4dBnjiuFh7OEWTu3RG6WhwGoA8Z|@FLMj+t3sY z(sD+tW#)DbS47>8ECnj-t*e3lga&6cHMEhWkL*|chto2vkqMDfgK2+Ro79BbS53h$ znIVL2tt7s+fwBC8+p?0{aV5mnOWcWu*(RAwn@{27zcnftERMP(Q2KqeZITD# zVyWZ%6zK!#-LVnyQ@VnlbY8g7Q#Xz2$(qxry+8@)1px3j^)i1BmAvS=m^Be225|mb zCEPBd`i!vcIn^IY0svrE4ANU0;1Oy_?e`7K_ncWo3k(3;Oek(uBFI_jM|I%S!s|3$jzd{%4i3{?oVxV+b7 zJZNw0`pKoMh*WdQHyqE8Stj#@+DGRZ(c4O2{G6M>qgvyM3pu&VlA0y2J~aVq&5t-}$O zZA(Om9fy-j#Uxk8Iu;b+fkz+B{7AlaN3q1;!39c(KAnD&X%2wQ&pQ${(#lNsXccX< zd_Jz+=({FK3^`&yP%S>fc&r`<8d5G44UVt`+hvznyGW^m2&Wq>%n3MQP_a!aYf`0czOFRN+wO!h7 zr6py@xwaRaShH^If2JN$VK);uDI}pHCE)3{MC5>Q<(bK&}fJ2LNu>@ZfPx^-jy9FA0tx(9lvtuUBK1 z`ukA_0CYn~;)Zv!Sh~wzrfbt9W}&VhaC6_YH~@&{RZa@igMOJnNfYW#N0Zf_F7c+SZq_v6*(0YZh-Rif z0Oa1tQU|<~Fucf$0YGo@>dr&u-{~Zf{|>jzNnB0L0f2_D$t;C#N>%@22mlyuENQ-D z0X?_W!SEAuvTfILbi#}q04T)(K<{mH>+XM9`!AC~)Z;5T78|BaGbgrT0KpAGs5| zt8kfxl$rC@fE55FzN5)pL!<7ZZ9k@gBNqVZp|q=BA+054FQt*P7l@K*8Yoxg$Vz{& z&EMwoNMlEmP=yC2-KMiIm{&+tf?j`~R!o^S;rI2T}bb8;#xVvR%_-k zr8kc;8c493={BLDx23OhTVfzSr#8E)kXj^M%Za@VPxV6%CPnad_JceNG$umPa|y_) zA7P+^+NyNVE(m5y9b`petdrhao4S9RVp*GL6^v;NoO@=`?!k$Lb+*q`oJno*y@M$7 zvAL{>&pj23C$YQ503KYnO3T$A?5dI^9+9+Kv6R}y6v2BXJLJhR0)iDm*Qr*tDYWx+B;vtcO}DWi21&bLV5qeOq?n5*K6 z^&Hfaj9H|z8M)$%aM?6QPD*Co%w?TB0Fd+SB>UXl#-y|+}#GpBzfJfI<6t7#^b9!mW^H_dm>&jEpeX| zY12{~;37AVW;HU^_?Oq+c(FLkYaIx)pXXZST9P5dHoY8Ze>wn=B&4p@b0SEqdP4T9 zRJ1xP0D!uEZ0v#%+ZU~4m)Tu&7!pZi1uERLXo(q&0|4UCsozrXMoWK*Si~9QjlZhhP#Yd6oRd2_ z20OB9T0s&Yo<}l~sb4riOt$W^bF07nNQHHLbL~BwHtaC0;f3ykYFc3x8l-*rg}A;YwCf@kJjtbxpHqKl(JqCYrh;?bmhI&i zxe5X5>Rk$!fFT3~>vJ;e3J{;ph-X%LV zKY>OvIpUdAt1Ew3B2(JqOPn=Lmx**cWKNL1Pyy!QP3APRMod`57}a@BCB^mH4eR&m zLZ|Uu<+2%v)XoJfN{Xm5e$}_dvLF;@{Mb~s%UA@FDcLF#f|^qoYot`E!>;RyDwIQ1 z+=JI5%n0|Rl9H+n^~@KkOqYxnJP)Q7>s6Yx_OZ+=Sy+F;l{(qf)WSjCpmJ*02B{^b zsm;u>T)NGUMEq&4-bC0{#7hgr5KHQEg6ccd;C8o7>mxjb)3@F($lR6b_SOS2|E4!P zrS-niL=+8T*q&~^b8RSAsIu->@wOLclcknxl9;DYrwZKrp=_;smnttx43_ui8)~IJiH2LbQDi}Z>DG7+3m?rO<_+Y`-e00u2*Yf5pEbK1b{Tq2+brT zpzWDwPQ3%XA^LC1sov#tjg$rpqrF-L0XR7k**7G<{m-p?$4%9mx~0asHpV9r(Z`^w zH6sob*D(!Z?u7$I7$F_TV1M(Qn-GvHar2c>3z z0{{{NMRdZ`%n30#d)W{G(#-d!&6a`~+|&Xf6kS87FybZs4x3jkUf2CK!zKEP?}NllQxAS)gR0L*JhQTSMDj+4JrZZ#F~ z;ZA>UD2O(j0J@WU=F}j%7Map~W`4^qR7T~w{ktmWE17(UCJ~r3g+^|nn)ypY?3k?( zx0@Q98)5NXk+08|5UHLddAa^QwfwK*Jc;D~bAl4&GQGf&+4ySvkY*&5pV+~X$#>&X zUUby2?<5|QS`E2P=tmly!ennj*{fA&kQRSg#QAe~R~eST7$K)DsDsEnQ<-M|!Q8-r z>WhqvIK`#^cyRL*QK%b@!vGt?pA5N;w4pRa}3h!yrb{OaVX^+TWCU!Tp@ZX;b@1$z($sF32p< zAMkRSb+_UxFl{vXEJj%-pL8Q!G=`=FN6f2(GT~Q7_wgQ!Uy$?9Vo@fuQOdjkIEhV1 zHHWB0rU2j;)utwYsR1C1Gz!IX13v+PgcKtO@mWqLM0;>7%)`YIfCTql_CSASu~J&! zM*ITZLt{fg%mIL;5CFu8xUX3e6me#8`>&d7NCj=(n&c$jGUg?^nFj!|v(UYYggF|B z3Ol+aqc9Dsx_gDRxaTma2y&VRZ7qkhg;8OJgvIv_DXo-EblxV<(idt;%lAjIc@Y3&B4U}R8RmZ$9||Q>K^18wL_vi%R0U_f<2|_)$T> zrNfmx=*M(3x_ZlzXJra#h2O$Bq1Y` z`xM)RnW@?0vHYIfF_T&u3WxAExW}~KUrkU#9G^6@3vnsS=^FLxBYC7Lj8yl#GzN*s zv0;{78eNXA{Y=OKxvzgJ<$Rq-cU5jwDq(h;pL+?(G-wbj+89dPP5X3+@08bLVO*xW zTNBsU@XDEA=#p<}l(0q9v5auZ3m&;u#s(rpw1zS&l&rwF5v?UO(J5`*b!d(%S!QyV zPI*sJ>$#_SNtG=#!OAD|%!H>i`w0N}4Lv;A-`F~clrDb4YN3DcY@~KbB@BeBgUq$4 zgl}5W03bP4eEup)F!8?qkswFpq7*GmxejMgu?+bX=;A zFdBgk>Nr&Oa~f-(B(xcRudnY5x}1Ncpgn?rQ9`8bWdz{-KMepZ1_0XEkULYm14`47 z2q3Y%2BbcLM~#26`t*Rz3f_O!%%-xB8qJca}Sq8kFIaYhzy+dZ<*^ty3yk9;b&I@R{M zLZu$PwOm%GsEA-olEwkRyOn7AD{0xe>s12=f(O|qPR)OK1oJF$*vceo&x6i*p*E?R ztLrWTm<|^WIVDyqm7MNz&yUb6Q^ZnIpZUtY=_X-FsxVY4(Fxp#1z=A10`tl-!4$%#CD&{O7eaffT3EEBKWJurV^ zXM5_^DX4!U0lg*?w{Vt)^~5G)ZPgKUMLccd4HXeol_U?2tB%Jbp=Hxt8r!@kLA=zq zwm5|aPNz6xwF7ypbv&fW1L%WO+D3XFA8%5>hspEgNkEMv+(3UDixJwhuKIKR2LiBV9 zd}+U877hO;MYLIo8@)*lTI95r-%$yVWG&nt@!*lHRJ_Jprb>sw!ju(1gxU6zzsrd8v^vID~tQ+A7Vu-#bmiH2PcFajO^0eO@Xvcn2v z>P>$z{>6FZRWv=N?oSK=EXOAaaHlTUCUc7plwGs6n~CWdlqHp~^+rt})~kQF1rdVy z8S^Uw0Dk#JGeP?s`QTACBnm0X=gE4R7yuMCE&2~m5#LEcFe-JM+jUYg=QNb;HT1Y8 z-E%ya@lQh*2RAX~IM>l9Kk(&@eJuij>;-=Sh%nIk+eB7C{$q`2%;>ohSy|B`yBah_ zxY=Z+PH@yCQcet?I3c-Z5!;;=_{~NnaZ!;&EWu9|V2I}QM#gADeluV1HLr==lw7B;tB(ueW@ph~(WWe7<5^1@ATxFw-n znKWzhHL0yz*ia7RmL33P5&%-uq>zOGfGKEY8s=yakOlFQ2$hKKH%zG#ug>nKP6nA+ zVZ$V(F<$-A$sU&&y~>2rCt%tfyQSFvTgI=_nii&!!pT|%R#N}5R;OmP9`q{^UI7bGDT&(iSlZL~jBE*c!V0$f zVRSvt@8Z@hx;ulch;Hu%hUCoEOf@Afc@|*;qRMk#K+O9orQwbO4l-C(3Gsho!Y(Hh z#O3itWBIVCt6}M!XbRn{ge)pom%AT#-#QAchnF!am0T(gYpS@LV;~f#siyNxCA(-I z>~mQlFpw(D&;_TIW!h|A5fFc{1{5Elh7sVZRFn{n3U`#`Co2{8N#Mp8$HDDPu$HPi zQIraxCWWb~D zhm&cSk}lTB-STA~FYgGt*PI&15IABUTb$sFyWOn3C>1|8818 z1c1c!0~G*(R|}Nb?PKE6FFQLSQhG%fjV30_0{gFQSxT9)Uf`m0Z}@9>-z7u9!;@xC`u^{TZ1{D%Z>*MtyGg=7zV&t7gTs7{|BNuwfB$HQEoE|3Xf658Z zVq|lEk9WcSb~Aqv^*SjKO2cS(Smf)b_!Cp8OxZV!x=9PHH(?v3^_>YR`j3-}?jntKXs8NKJoj4?!lg4`3!VWa&H;s~x5^ ze1+k+&0@AF1u12!#-nNE@|e|7Cx}R;xR`2oN=Zcahq3UFUW$KGx=`-fLlLGdfZ<&mw{qT5_3$_u!i&nt%icN znuS_qFOR7%T2FEShP7%@hF4ebB@6e;#nkJGCitREy{YcDO#E1H;+41YV8Iti z>IQ#orUeC{&egF36^h7X73(mFMo_cVb4i0|#!%lRfr+kj?l(1)OGw#I!|TlDKwv@1 zga3dR9N}frE#?;IL~Rg@bNk0dD^m|qsIwd#-z>${>+tuOK7($6v?v|qG$9j7z{~|V z*EvcHk5d$2@zn|`L}d|<<u37e?&|N{1jT%5&T-#gVSFz%@?K+Pr z=M)+dZ=Dlk#6isqCV>FDB?b7ApnH8mb?Aap|Ois=J=W|#VaFfyNe2l{Z5U@9wi_! zh~&)K3-ikY%=k|MKv6Q_rRI*8L#uxU_P@CLI*7M=k1>z&~rn*x%oB(XuJi zjh)0G+$)Nu0FXptnq*mf08q8bXZl4K08D>_DfDpxpjr)F~`y)zcyWTmlkFCGE2IQ;VBJsk@x zuL~mkUaLST@?gq}q9t40OCo=H%)Km&EvSO+dAO=F!aCvxE0ZFj<7fwfUzBZ$A_^Wq zf99vm+#y z(Z3yGrzSmG06kG1TWiQz7gaF`+{P0+f8Xc`m zlEi6%k9j3#L2G_i$TfeIMM5zz79n`s;R5r|!W&i`4fTCL&b?W4L$R?NK=Wg1f%lcf z82zJbqlg8{>kkj~N-Yetzss{I^TyxXg1DTMK6w}SVrPFo=J}@yE-3;4-sJ0p zR*UG){8I#-RlzaCR4oe+%Zp=Zek9RNMH`!5=fx#1g*2naw8hs%fv;`Ny=4Auyy#Zw z0`<5H!wp5dzq^YA0O#TCavpV}W8J?Y_)r&*$EP=3Lj@Ws?1hwJQ6#xIy$~~O?$L;! zNpU)L^#<6BchrAd%4uO&OXSh=tQRBvh&DYceS~-rz_+QCYS|u#dkl%}C*cYg0FuBy zghk#jb<}en`iOS0JlsaJ!f>nWP7()6(kEel!KFiA?MPp~o z_sh_L#%9QR+kk||R39ZqcGx=0nbDmMPOWkmPD4JLoQa79jl&qILBp(%_}eg=fJ z%(r|z7C2-<6EbDme+dA1;1Z_HYmbNs-6chv9p5Mw1ArGCcb2JaV=e{&Qjec$qNuTuyydNgQu zcgGO}0LOoP$TcuWzWYL3qt($M08l4=aV(C84a611%ASHBYxa(yr&JKTTX|z6K1&h&0al}iJ zrXV2_UU?DSbj6X4Q$=fJ5{ZymOb>#RI2+jm9*uuhnjxjp6(EX>O5`jQ1nsTzWJ!3; zQEV#45&CA5_&%R^HOABBd67PFP!-_R2pc%Ta~^4c z_E)wMG4^hsRyxag(5>y?Wh)#%$4T#ZRX2#tNje!l5MK0zN1wVFL?^VOx#Eni@^ha& z2pNAxi-n6leivHv>~HJ}>O9trMmeyw-yQ9W3^tOsNY3j7NhK+CYDd_}iY=M8&gFt< z*cu0-cbFMjB?H=2YMpNVyk|qQAJik}oTa`P`A>HPX=b!9{*L{R0D$j^*9!oEzi|9= zl+J($FhD!7{5%{1fV!@#Pj!2Z7j>+=jFW#}H8#)wUT~GU8J#3iZC?>-9z840OsAeI z_FU{qu^gdH7YDnPt*Ko$NvQdkP;YlmJ0)|(@hg+k)1cm??tAL`r)Ko_*S(-Q_dPu3 zyH*7)X5}oFrDP5}soz@=rP0;;5dK!fYBmHh9I{^P^(+7YpPA0FRC7V}Ak|zS+BScd z>D5J6ngG%{Le;8|FjqGK5JO9DsP7{H5Jsu%b)#nihi+&9un15IFK2FU?uBA+7Te;K z*-HQ*ykqgoXirTM0?gGT-Nijd>E4vR6W+bqC}9 z_(h$jF$x3L;y$^kLDr-`h36C3>os!M=F9-fFM1f}B+hf3#~k;$$eRj#%TbD3M{dbL zrwz%veu9l0u;L+`zCO|2+-S_%iO&7rxhidd%jX;_TGivCF1aS86i`*|m)w7RZB8+# zl8a8P%Bv>XHjErq|GAlyPdBdgxw$-)5237K;-aj~QKg`0!c2WVav$rSgox*i==&?L zlvRG>c^Z-sO(76{ITw|OtO9OLUJ@H|K`uJxgjOoHqA#cCg!ygG1xv)9sY%l+n%r1_ ztW=R(E^#dts(Ll2fgBKB+)aP|?ws$T(JPaE_Ys?{$#l>^Xt-f3@f~ip4)Ogt)$H#% z2iD-Zr&D2w<{*y=c=aDB^ zeo)`0Tu-REYq{{^D`uTjYtRVhvx@Zml{}Y00)eW{oEs(HP^(bc2sb|};0f=0^xEqWJf{EOJ$#2meu>F=fU_Ena zbLf_;;gr5}XM@3=z-vyniJV6!uc<#-vjfBbz$t1m!Vo#n<~U0K)s4u6u_H4EIosyo zk((){<$^4t8Dzt`2r+*n_6w;IbcN?${=H81jO8cgBDxK$?X07yi0v4g1z58qy;*<5HNZ8!JZc2S%rVXF zt9cnNs|xSlJas_11W9m$98C>?j6*FO^Y?}$iQ)pTy`$z_X4T14YUjj^7YASSR+YIm zLNr#LKF^z+9uW^ZrzN_TMWN3;T?}~;Xp-M@?+pwCkEov(|K5o+Haw7%^P*L+)KuHq z%f-NR@hlVL$;B%`>4azIiPs-+tzkpiefirf-r&uJ{|l8l;AC5#=u!Xx002ovPDHLk FV1n-6xJ>{6 delta 462352 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

F!b^VpG*KjWz`zm*WlAjI~ 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%0D=HMHUJQ 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