diff --git a/AGENTS.md b/AGENTS.md index 5d790b9c..cda29a70 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,3 +49,13 @@ 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 + +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 9d8a0cb9..b7c482e8 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,9 +14,13 @@ 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 + +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 @@ -72,26 +76,38 @@ flowchart LR | --- | --- | --- | | In-process native module | the same peer link as a process app, through Makepad's `OctosPeer` client (the module host claims the link for the instance that opened it) | on `main`; no module uses it yet | | In-process native module (Rinx) | the injected `OctosAppService`: `open_conversation` (the app's conversation with its agent) and `open_context` (a per-client request context, such as a Rinx mini app) | on `main` | -| Script app, and its cards | `host.request("octos.session.open" / "octos.session.history" / "octos.turn.start" / "octos.turn.interrupt")` to the `octos` host service, for the names its manifest declares; a card's in-card chat (`sys.chat`) through the shell | on `main`, after first-use consent (the shipped gate; `OCTOSENSE_CONTAINED_APPS=1` asks nobody, `0` turns it off). Today's system apps with an agent declare no `octos.*` name: the shell drives their agents | +| Script app, and its cards | `host.request("octos.session.open" / "octos.session.history" / "octos.turn.start" / "octos.turn.interrupt")` to the `octos` host service, for the names its manifest declares; a card's in-card chat (`sys.chat`) through the shell | on `main`, after first-use consent (the shipped gate; `OCTOSENSE_CONTAINED_APPS=1` skips first-use consent, `0` turns it off). Today's system apps with an agent declare no `octos.*` name: the shell drives their agents | | Process app | the peer link on its hub connection (`octos.session.open`, `octos.turn.start`, …), identity stamped by the shell | shell side on `main`; no process app granted an agent yet | | The system agent | the kernel's own session `_main:api:octosense#system`, reached from the shell's system chat | on `main` | | Talk to Octos client | the system conversation only, with the external token | on `main` | ### 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 and `glance` | `news.list`, `news.read`, `news.notify` (the `news` host service) | a notice card with a notification | +| 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 | -| Photos, Maps, YouTube (`os.photos`, `os.maps`, `os.youtube`) and Camera (`os.camera`, phone only) | each app's `bundle/tools.json`, the manifest's `agent` block and `glance` | `.notify` (`photos.notify`, …; the shell's notice service, `crates/shell/src/glance_notice.rs`, since these apps have no service of their own) | 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`). The broker identifies the app as `card.`; the kernel returns its peer slug during preparation. 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. -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. +`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**: @@ -180,7 +196,7 @@ The person is not limited to the system agent: they can talk to any app's own ag | --- | --- | --- | | **"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 that declares a chat | The person types in the card; the publishing app’s own agent answers, with its reply marked AI-written. See [in-card chat](#in-card-chat) for current availability and the demo. | -| **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 for them the "Ask " panel is the way in. | +| **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: @@ -231,7 +247,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). @@ -305,9 +321,9 @@ 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); 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 240a6809..5ba248fe 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,9 +14,13 @@ > **要开发 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))。 +## 从代码导读开始 + +初次阅读源码?从[从应用窗口到 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)。 ### 进程与连接 @@ -72,26 +76,38 @@ flowchart LR | --- | --- | --- | | 进程内原生模块 | 与进程应用相同的 peer link,经 Makepad 的 `OctosPeer` 客户端(模块宿主把链接归给打开它的实例) | 已在 `main` 上;尚无模块使用 | | 进程内原生模块(Rinx) | 注入的 `OctosAppService`:`open_conversation`(应用与自己 Agent 的对话)和 `open_context`(每个客户端一个请求上下文,例如 Rinx 小程序) | 已在 `main` 上 | -| 脚本应用及其卡片 | 向 `octos` 宿主服务发送 `host.request("octos.session.open" / "octos.session.history" / "octos.turn.start" / "octos.turn.interrupt")`,限于其 manifest 声明的名称;卡片的卡内对话(`sys.chat`)经过 Shell | 已在 `main` 上,需用户首次使用时同意(发布时的默认闸门;`OCTOSENSE_CONTAINED_APPS=1` 不询问任何人,`0` 关闭)。如今带 Agent 的系统应用都没有声明 `octos.*`:它们的 Agent 由 Shell 驱动 | +| 脚本应用及其卡片 | 向 `octos` 宿主服务发送 `host.request("octos.session.open" / "octos.session.history" / "octos.turn.start" / "octos.turn.interrupt")`,限于其 manifest 声明的名称;卡片的卡内对话(`sys.chat`)经过 Shell | 已在 `main` 上,需用户首次使用时同意(发布时的默认闸门;`OCTOSENSE_CONTAINED_APPS=1` 跳过首次使用同意,`0` 关闭)。如今带 Agent 的系统应用都没有声明 `octos.*`:它们的 Agent 由 Shell 驱动 | | 进程应用 | 其 hub 连接上的 peer link(`octos.session.open`、`octos.turn.start` 等),身份由 Shell 标注 | Shell 一侧已在 `main` 上;尚无进程应用被授予 Agent | | 系统 Agent | 内核自己的会话 `_main:api:octosense#system`,从 Shell 的系统对话进入 | 已在 `main` 上 | | Talk to Octos 客户端 | 只能用系统对话,使用外部 token | 已在 `main` 上 | ### 系统 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` 块和 `glance` | `news.list`、`news.read`、`news.notify`(`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` 宿主服务) | 一张通知卡片,并发出一条通知 | -| 照片、地图、YouTube(`os.photos`、`os.maps`、`os.youtube`)和相机(`os.camera`,仅手机端) | 各应用的 `bundle/tools.json`、manifest 中的 `agent` 块和 `glance` | `.notify`(`photos.notify` 等;由 Shell 的通知服务应答,`crates/shell/src/glance_notice.rs`,因为这些应用没有自己的服务) | 一张通知卡片,并发出一条通知 | -| 日历(`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`)。Broker 用 `card.<应用 id>` 标识应用;内核在准备 peer 时返回 peer slug。用户只需在首次使用面板上允许一次(从 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: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.md`、技能和触发器([ADR 0002(英文)](docs/adr/0002-event-driven-app-agents.md))尚未实现:应用 Agent 只在系统 Agent、用户或卡片请求时运行。 **从系统 Agent 到 glance 屏幕上的一张卡片**: @@ -180,7 +196,7 @@ 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 绘制自己的助手界面;系统应用都不绘制对话界面,所以对它们来说,入口就是 “Ask ” 面板。 | +| **应用自己的界面** | 原生模块的 `open_conversation`、脚本应用的 `octos.session.open`、进程应用的 peer link | 在应用内。Rinx 绘制自己的助手界面;系统应用都不绘制对话界面,目前通过 “Ask ” 面板与它们的 Agent 对话。 | “Ask ” 面板的行为: @@ -231,7 +247,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)。 @@ -305,9 +321,9 @@ 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` 中的工具已端到端提供给它的 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..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 @@ -80,7 +82,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 +109,21 @@ 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. + +## Changing tools and data access + +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. + +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 30e69033..91b5f1da 100644 --- a/apps/README.md +++ b/apps/README.md @@ -2,7 +2,9 @@ English | [简体中文](README.zh-CN.md) -> **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). +**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.** 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 @@ -10,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. @@ -24,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. @@ -66,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 | @@ -107,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. @@ -153,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. @@ -177,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 @@ -368,6 +371,14 @@ model lane and tools. Which system apps have one, and how | Photos, Maps, YouTube, Camera | `agent` block, `glance` | `photos.notify`, `maps.notify`, `youtube.notify`, `camera.notify` (act, background) | the shell's notice card | | AI providers | none | none yet: App Hub takes a tool namespace only as `[a-z0-9_]` (and octos a tool name's segments only as `[a-z][a-z0-9_]`), so `ai-providers.notify` is refused | – | +**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-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 for another app's shareable tool), and `bundle/tools.json` declares the @@ -398,9 +409,10 @@ model lane and tools. Which system apps have one, and how 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 @@ -422,7 +434,7 @@ model lane and tools. Which system apps have one, and how 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 @@ -470,8 +482,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` @@ -556,7 +567,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 81bd86d9..34facacf 100644 --- a/apps/README.zh-CN.md +++ b/apps/README.zh-CN.md @@ -2,16 +2,18 @@ [English](README.md) | 简体中文 -> **在整个系统中的位置。**系统应用是运行在 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)。 +**初次阅读源码?**先读[桌面、Home、ROM 与系统应用导读](../desktop/docs/code-walkthrough.zh-CN.md),再读 [Agent 与 Tokio 导读](../docs/architecture-walkthrough.zh-CN.md)。前者追踪启动、原生托管、脚本 bundle、应用数据和 Android 平台边界。 + +> **在整个系统中的位置。**系统应用在 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 运行。应用拿到的是邮件, @@ -22,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` 时才链接它,默认不随产品发布。 @@ -58,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 内核 | @@ -91,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。 @@ -128,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`) @@ -147,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 模块 @@ -326,6 +330,12 @@ Shell 把日历 Agent 的 `calendar.*` 工具当作这个系统应用自己的 | 照片、地图、YouTube、相机 | `agent` 块、`glance` | `photos.notify`、`maps.notify`、`youtube.notify`、`camera.notify`(act,后台) | Shell 的通知卡片 | | AI providers | 无 | 暂无:App Hub 只接受 `[a-z0-9_]` 形式的工具命名空间(octos 也只接受由 `[a-z][a-z0-9_]` 段组成的工具名),所以 `ai-providers.notify` 会被拒绝 | – | +**宿主服务 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`)、 @@ -345,8 +355,9 @@ Shell 把日历 Agent 的 `calendar.*` 工具当作这个系统应用自己的 面板的“停止”只停止用户自己的回合。手机上还没有打开这个面板的触控入口。详见根目录的 [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), @@ -359,8 +370,7 @@ Shell 把日历 Agent 的 `calendar.*` 工具当作这个系统应用自己的 - **试一试**(桌面端):打开助手(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 内核 @@ -401,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` @@ -477,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 0a7f4c66..7320f21f 100644 --- a/apps/appcard/AGENTS.md +++ b/apps/appcard/AGENTS.md @@ -50,3 +50,13 @@ 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). + +## Integrating with the shell + +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 c45f6309..814c8799 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/`): @@ -42,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 a27d097d..753d7477 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/`): @@ -38,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.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..710405e0 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-的实际执行模型)。 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 new file mode 100644 index 00000000..7aed45e6 --- /dev/null +++ b/desktop/AGENTS.md @@ -0,0 +1,23 @@ +# Working on the desktop product + +Follow the [repository rules](../AGENTS.md). Use the +[product walkthrough](docs/code-walkthrough.md) to trace startup and hosting. + +- 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 a9a79019..e4d7c4cc 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, 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). 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..10f4ba6e 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..c8e32893 --- /dev/null +++ b/desktop/docs/code-walkthrough.md @@ -0,0 +1,307 @@ +# Walking through the desktop, Home, ROM and system apps + +English | [简体中文](code-walkthrough.zh-CN.md) + +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. + +**Launch recipes: unverified.** Prepare dependencies with the root README's setup +instructions first; use its sources-hub configuration to reuse existing clones. + +## 1. Locate the running components + +| Component | Entry point and responsibility | +| --- | --- | +| 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 +# Standalone Reference window. +cargo run --locked -p octosense-reference + +# Reference linked into the desktop and opened at startup. +MAKEPAD_WM_TEST_APP=reference cargo run --locked -p octosense --features app-reference -- --module reference + +# Standard desktop: App Hub, Rinx, Terminal and kernel integration. +cargo run --locked --release -p octosense +``` + +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` 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), + 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 +[`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. +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 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 path with your OctoSense checkout. +cargo run --locked --release -p octosense-card-host --bin card-host -- --bundle /path/to/OctoSense/apps/news/bundle --system +``` + +`--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`; 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. + +[`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. + +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 a tool into app data and Glance + +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 + 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 [`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. + +The shipped declarations provide these operations: + +| 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 | 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 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), +[`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 +# 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` 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 +[`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 new file mode 100644 index 00000000..4e7e6377 --- /dev/null +++ b/desktop/docs/code-walkthrough.zh-CN.md @@ -0,0 +1,261 @@ +# 桌面、Home、ROM 与系统应用源码导读 + +[English](code-walkthrough.md) | 简体中文 + +沿着可执行程序入口,追踪应用托管、数据访问和 Agent 交互。以下路径相对于仓库根目录。 +[Agent 架构导读](../../docs/architecture-walkthrough.zh-CN.md)继续介绍内核、peer、工具路由和 Tokio 任务。 + +**启动配方:未验证。** 先按根目录 README 准备依赖;已有框架克隆时,通过其 sources hub 配置复用。 + +## 1. 找到运行中的组件 + +| 组件 | 入口和职责 | +| --- | --- | +| 桌面 | `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`。 | + +隔离应用的 `main.splash` 使用 Makepad Script/Splash。L0 `.card` 文件经过 Octoscript +独立的解析/检查器,再通过 lowering 转为 Makepad 可渲染内容。产品中同时使用这两条路径; +阅读或修改某个文件时,沿着它实际的加载路径追踪。 + +## 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`;`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 + +桌面会打包选定的系统 bundle;可以从启动器打开 News 或 Calendar。 +单独预览时,先按 App Hub 仓库的说明准备依赖,然后在该检出目录运行 `card-host`: + +```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 需要完整 Shell。 +例如,在 OctoSense 根目录运行 Mail 的演示服务: + +```sh +MAKEPAD_APP_CONFIG='{"mail_demo":true}' cargo run --locked --release -p octosense +``` + +演示账号密码为 `demo`,发送留在演示环境。新商店应用在 OctoScript-App-Design-Flow 中开发, +使用 App Hub 的准入/发布流程。[本地目录配方](../README.zh-CN.md#发布前试用自己的应用) +用于发布前验证安装到 Shell 的路径。 + +[`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 助手使用自己的模块。 + +准入将 manifest 的能力请求解析为策略。脚本的 `host.request(...)` 按应用身份执行。 +App Hub 的 `crates/appstore/src/services.rs` 定义 `HostService`、`ServiceCall` 和回复机制; +调用携带应用身份和宿主目录,供服务检查。只有明确声明的 Agent 工具,才会把相应操作提供给模型。 + +## 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 + 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: 请求 Calendar 添加日程 + A->>R: calendar.add_event 和结构化参数 + R->>R: 检查调用者、授权、schema 和策略 + R->>C: 以 os.calendar 身份执行 + C->>D: 读取、校验并保存 + C-->>R: 对象结果(id/start) + R-->>A: 工具结果 + A-->>H: 回答原会话 +``` + +[`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 的应用 | 工具与实现 | +| --- | --- | +| 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` 中列出带点号的工具名,所有者必须声明可共享, +relay 也必须授权。准入还检查 `HostLimits.offered_tools`:默认提供的工具中没有 +`mail.send` 等名称。先补齐声明、准入 offer 和执行器路径,再将其写成可用的集成方案。 +[Agent 导读](../../docs/architecture-walkthrough.zh-CN.md)继续解释委派和向其他 Agent 请求帮助。 + +## 5. 追踪人的对话 + +桌面上聚焦拥有 Agent 的应用,从栏按钮、Shift+F8 或菜单打开 **Ask <app>**。 +F8 打开系统 Agent。`agents.list` 报告应用 Agent;`agents.ask` 等待首次同意和 peer +准备完成,再返回 peer slug。系统 Agent 用 `peer_send_input` 发送任务,用 `peer_gather` +获取答案。声明了 `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)、 +[`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_APP_CORE_BIN`,并在 AI providers 中设置提供方; +`octos-core` 在构建中启用集成。详见[内核指南](../../crates/kernel/README.zh-CN.md)。 +Android 打包 `liboctos.so` 并作为子进程运行,OpenHarmony 在进程内运行内核。 +应用 UI 托管与内核托管分别选择。 + +## 6. 追踪 Home 的设置和平台桥接 + +在 **`phone/` 中运行 Cargo**,让其 `.cargo/config.toml` 选择手机版 bundle: + +```sh +cargo run --locked --release -p octosense-home --features mobile-only +# 同时链接 Reference 和 Sheets。 +cargo run --locked --release -p octosense-home --features mobile-only,mobile-apps +``` + +[`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 4a3ba81b..5184168c 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. Status descriptions refer to this checkout; use the [Cargo.toml](../Cargo.toml) dependency pins when following external code. Dated runs below are historical validation records. +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). Status descriptions refer to this checkout. Dated runs below are historical validation records. Earlier source reviews took place on 2026-09-28 (OctoSense `ad0d738`) and 2026-09-29 (`baa90bd`). Those dates do not date the current status table. @@ -29,15 +29,15 @@ For the whole system around it (processes per platform, agents, protocols, tools | 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/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) | -| Contained script apps (system or store) asking the assistant | Available in shells that host a kernel ([#106](https://github.com/OctoSense-org/OctoSense/pull/106)): each app gets its own peer after first-use consent. Tool approvals use the shell’s approval sheets. `llm` remains a provider-management service for `os.*` apps only | [Consent settings](#contained-app-consent); [calls and replies 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/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, 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: 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) | +| Native apps in their own process reaching their agent (the peer link, ADR 0004 §5) | Makepad’s client and the shell’s `crates/shell/src/peer_link/` are implemented. No process app currently requests its own agent; Terminal declares tools but does not request a peer. | [architecture § An app and its own agent](architecture.md#an-app-and-its-own-agent) | ## Architecture @@ -52,6 +52,7 @@ flowchart TB 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)"] @@ -74,6 +75,9 @@ flowchart TB runner -- "octos.* service
broker identity 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 ``` @@ -107,7 +111,7 @@ 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. `Policy::shipped()` grants the four services only to `rinx` among native modules. +The host **policy** grants exact native `octos.*` services from the generated `native-apps.json` declarations (currently Rinx). #### Contained-app consent @@ -116,7 +120,7 @@ Contained apps use first-use consent by default. The environment variable `OCTOS | Setting | Behavior | | --- | --- | | Unset (default) | Ask the person before an app first uses its agent (`ContainedGate::Consent`). | -| `1` | Developer override: skip first-use consent. Individual tool approvals still follow their own rules. | +| `1` | Developer override: skip first-use consent. Declared-service limits and individual tool approval rules still apply. | | `0` | Turn off the `octos` service for contained apps. | On first use, the shell shows what the app’s agent may read and use and where the model runs. **Settings → Assistant → Approvals** lists each app’s agent and lets the person turn it off. @@ -192,16 +196,18 @@ 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 News bundle declares it (`apps/news/bundle/manifest.json`) and reads from it when `host.has("news")` | +| `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` | Apps declaring the exact `octos.*` service names, in a shell that hosts a kernel, subject to [contained-app consent](#contained-app-consent) | The app’s assistant, reached through a host-owned peer. The broker identifies the app as `card.`; `peer/prepare` returns its kernel-issued peer slug ([`contained.rs`](../crates/ai-host/src/contained.rs), [#106](https://github.com/OctoSense-org/OctoSense/pull/106)). Call rules are below. | -The four `octos.*` calls have separate argument, approval and reply rules: +The four `octos.*` calls have separate argument, origin, approval and reply rules: -- **Arguments.** `octos.turn.start` requires non-blank `text` of at most 32 KiB. It also accepts optional `trigger` (`person`, `app` or `incoming`) and `from`. The other three calls accept only `{}`. -- **Tool approvals.** Peer tool requests go to the shell’s approval router and its sheets (ADR 0004 §8). Developer mode answers them for the apps it covers. A host without a router declines them and lists them in `denied_approvals`. See [`host_approvals.rs`](../crates/app-peers/src/host_approvals.rs). +- **Arguments.** `octos.turn.start` requires non-blank `text` of at most 32 KiB and accepts optional `trigger` (`person`, `app` or `incoming`) and `from`. The other calls accept only `{}`. +- **Origin.** `trigger: "person"` is classified as `AppSaysPerson`. It is an app assertion, not a trusted human gesture, and cannot bypass approval. +- **Approvals.** Both host-tool and other peer approvals route to the shell. Existing grants and approval rules still apply; developer mode answers for the apps it covers. A host without a router declines requests and lists them in `denied_approvals`. See [`host_approvals.rs`](../crates/app-peers/src/host_approvals.rs). - **Replies.** The host refuses replies larger than 2 MiB. The response table below lists successful calls and common errors. 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: @@ -218,11 +224,9 @@ A script's own assistant calls use declared `octos.*` services. Separately, the | `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) | -**Historical validation record.** 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. -An app has an agent if it declares an `agent` block, declares `octos.*`, or ships `tools.json` ([#184](https://github.com/OctoSense-org/OctoSense/pull/184)). Once the person allows it, the shell prepares a peer with the bundle’s tools. The broker uses `card.` as the app identity; the kernel returns the peer slug. The person can then talk to it in the shell’s “Ask <app>” panel. See [`crates/shell/src/agents.rs`](../crates/shell/src/agents.rs). - -App Hub admits the manifest’s `agent` settings and clamps them to its limits. The shell keeps the admitted generic tools (`ask_user_question`), but does not yet apply the permission profile, iteration or token limits, or install `AGENT.md` or skills. Rinx refuses to import a bundle that declares an agent. +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) @@ -240,13 +244,15 @@ App Hub admits the manifest’s `agent` settings and clamps them to its limits. | 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: 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 [architecture](architecture.md). | +| 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 +The build/launch recipes below are **unverified**; read dependency versions from the root Cargo.toml. + ### Desktop, with a throwaway kernel and profile 1. Build the desktop kernel from the OctoSense repository root. The existing helper reads the octos revision from `Cargo.lock` and uses its own `target/octos-kernel/` directory, leaving other checkouts alone. The build and subsequent launch steps are **unverified**; only the `--plan` output was checked for this revision. diff --git a/docs/ai-services.zh-CN.md b/docs/ai-services.zh-CN.md index b191ab6c..f30065f6 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 和工具。状态说明以当前检出为准;阅读外部源码时使用 [Cargo.toml](../Cargo.toml) 的依赖锁定版本。下方带日期的运行信息是历史验证记录。 +本文介绍 OctoSense 的 octos 内核、提供方配置、应用 peer 和工具。阅读外部源码时使用 [Cargo.toml](../Cargo.toml) 的依赖锁定版本。调用链与执行模型见[架构导读](architecture-walkthrough.zh-CN.md)。状态说明以当前检出为准。下方带日期的运行信息是历史验证记录。 历史源码评审分别在 2026-09-28(OctoSense `ad0d738`)和 2026-09-29(`baa90bd`)进行;这些日期不代表当前状态表的更新时间。 @@ -29,7 +29,7 @@ | 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) | | 在 Shell 内核上运行的 AppCard("Ask anything") | 目前可用,需主动开启(`--features app-appcard`),不随产品发布 | [`apps/appcard`](../apps/appcard) | -| 隔离运行的脚本应用(系统应用或商店应用)向助手提问 | 在托管内核的 Shell 中可用([#106](https://github.com/OctoSense-org/OctoSense/pull/106)):用户首次同意后,每个应用获得自己的 peer。工具审批使用 Shell 的审批面板。`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`: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) | @@ -49,9 +49,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(原生,需主动开启)"] @@ -74,6 +75,9 @@ flowchart TB runner -- "octos.* 服务
broker 身份 card.<应用 id>" --> broker rinx -- "类型化工具" --> bus bus -- "confirm: host 调用" --> router + kernel -- "peer/tool/call" --> relay + relay --> runner + kernel -- "approval/requested" --> router router --> person ``` @@ -107,7 +111,7 @@ 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`。 +宿主**策略**从 `native-apps.json` 生成的声明读取原生 `octos.*` 精确授权(目前是 Rinx)。 #### 隔离应用的首次使用同意 @@ -116,7 +120,7 @@ flowchart TB | 设置 | 行为 | | --- | --- | | 未设置(默认) | 应用首次使用自己的 Agent 前,先询问用户(`ContainedGate::Consent`)。 | -| `1` | 开发者覆盖设置:跳过首次使用同意。每次工具调用的审批仍按各自规则处理。 | +| `1` | 开发者覆盖设置:跳过首次使用同意。已声明服务的限制和每次工具调用的审批规则仍然有效。 | | `0` | 为隔离应用关闭 `octos` 服务。 | 首次使用时,Shell 会说明应用的 Agent 可以读取和使用什么,以及模型在哪里运行。**设置 → 助手 → 审批**列出每个应用的 Agent,用户可以在此关闭它。 @@ -190,16 +194,18 @@ 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` 等),不使用模型。News 应用包声明了它(`apps/news/bundle/manifest.json`),并在 `host.has("news")` 时从中读取 | +| `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` | 声明了确切 `octos.*` 服务名的应用;需要 Shell 托管内核,并遵守[隔离应用的首次使用同意](#隔离应用的首次使用同意)策略 | 应用自己的助手,经由宿主拥有的 peer 访问。broker 用 `card.<应用 id>` 标识应用;`peer/prepare` 返回内核分配的 peer slug([`contained.rs`](../crates/ai-host/src/contained.rs),[#106](https://github.com/OctoSense-org/OctoSense/pull/106))。调用规则见下文。 | -四个 `octos.*` 调用的参数、审批和回复各有规则: +四个 `octos.*` 调用的参数、来源、审批和回复各有规则: -- **参数。** `octos.turn.start` 必须提供非空白、最多 32 KiB 的 `text`。还可以提供 `trigger`(`person`、`app` 或 `incoming`)和 `from`。其余三个调用只接受 `{}`。 -- **工具审批。** peer 的工具请求交给 Shell 的审批路由及其面板(ADR 0004 §8)。开发者模式会为它覆盖的应用作答。没有审批路由的宿主会拒绝请求,并在 `denied_approvals` 中列出。详见 [`host_approvals.rs`](../crates/app-peers/src/host_approvals.rs)。 +- **参数。** `octos.turn.start` 必须提供非空白、最多 32 KiB 的 `text`,还可以提供 `trigger`(`person`、`app` 或 `incoming`)和 `from`。其余调用只接受 `{}`。 +- **来源。** `trigger: "person"` 会得到 `AppSaysPerson` 分类。它只是应用的声明,不是受信任的人类操作,也不能绕过审批。 +- **审批。** 宿主工具审批和其他 peer 审批都交给 Shell;工具仍受已有授权与审批规则约束,开发者模式会为它覆盖的应用作答。没有审批路由的宿主会拒绝请求,并在 `denied_approvals` 中列出。详见 [`host_approvals.rs`](../crates/app-peers/src/host_approvals.rs)。 - **回复。** 宿主拒绝超过 2 MiB 的回复。下表列出成功调用及常见错误的返回内容。 脚本自己的助手调用使用已声明的 `octos.*`;Shell 也可以根据 `agent`/`tools.json` 驱动 peer,而不要求脚本声明这些 UI 调用。脚本服务调用的回复: @@ -216,11 +222,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.*` 调用的参数和返回形状。 -声明了 `agent` 块、声明了 `octos.*` 或附带 `tools.json` 的应用都有 Agent([#184](https://github.com/OctoSense-org/OctoSense/pull/184))。用户允许后,Shell 用应用包中的工具准备 peer。broker 用 `card.<应用 id>` 标识应用,peer slug 由内核返回。用户随后可以在 Shell 的“Ask <app>”面板中与它对话。详见 [`crates/shell/src/agents.rs`](../crates/shell/src/agents.rs)。 - -App Hub 接受 manifest 的 `agent` 设置,并按自己的限制裁剪。Shell 保留获准使用的通用工具(`ask_user_question`),但还不应用权限档位、迭代或 token 上限,也不安装 `AGENT.md` 或技能。Rinx 会拒绝导入声明了 Agent 的应用包。 +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) @@ -238,13 +242,15 @@ App Hub 接受 manifest 的 `agent` 设置,并按自己的限制裁剪。Shell | 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 | 已实现人类/系统通道、Ask-app 面板、`sys.chat`、宿主路由的问题/审批及 peer/context 记忆。见[导读](architecture.zh-CN.md)。 | +| 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)。 ## 本地运行与测试 +以下构建/启动配方 **unverified(未验证)**;依赖版本取自根 Cargo.toml。 + ### 桌面端:使用临时的内核与配置 1. 在 OctoSense 仓库根目录构建桌面内核。现有脚本读取 `Cargo.lock` 锁定的 octos 版本,并使用独立目录 `target/octos-kernel/`,不会切换其他检出的分支。构建和后续启动步骤均**未验证(unverified)**;本次只检查了 `--plan` 输出。 diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md new file mode 100644 index 00000000..0e97e8e6 --- /dev/null +++ b/docs/architecture-walkthrough.md @@ -0,0 +1,295 @@ +# Code walkthrough: from an app window to an agent turn + +English | [简体中文](architecture-walkthrough.zh-CN.md) + +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. + +We will use one question throughout: **“What is on my calendar today?”** On desktop, a person can ask the system assistant to delegate it to Calendar, or ask Calendar directly through “Ask Calendar”. Both routes can reach `calendar.events`, but their answers return to different conversations. This is an illustrative tool path: it requires a configured kernel/provider and consent, and the model chooses whether to call the tool. + +## 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 a separate memory area under the peer’s 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. | + +The companion code tours cover [Design Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/218b25d2460d64f843932f67d419467618464fb9/docs/CODE-WALKTHROUGH.md), [App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/19bb52d402e80e89e085dea989615e3ec612d359/docs/CODE-WALKTHROUGH.md), [Octoscript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad/blob/fb29b6b1cb6e16f38d99a8aef60431a9565dfd59/docs/architecture-walkthrough.md) and [octos](https://github.com/octos-org/octos/blob/82900bf149d3a53016c1c1492ffc075d2d4fb0ed/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 + +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 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. | +| 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. **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 +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 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 + +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. 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. + +## 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 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` opens first-use consent and waits for a ready peer slug—the identifier issued by the kernel for that peer. 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 + +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. The event sink is the callback that receives progress, replies and completion as `ContextEvent`s. +- `ContextSpec`: host-authenticated account, instance and granted service names. +- `Broker`: the shell adapter that connects app requests to the kernel. It holds the 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. + +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. + +In the Calendar example, delegation runs on the system lane; “Ask Calendar” runs on a human lane. The **blackboard** below is the kernel’s shared record of peer work and results, which the system agent can read with `peer_gather`. + +```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`. 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 a control to open the Ask-app panel. App-owned chat and published-card chat remain separate surfaces. + +Stopping work depends on the entry point: + +| Action | What it interrupts | +| --- | --- | +| Ask-app panel’s Stop | The human lane | +| “Stop the system agent’s task” | The system lane | +| Lower-level `ContextOp::Interrupt` | Can interrupt both lanes | + +Hiding the Ask panel keeps its context and subscription. Changing app or revoking access closes them. + +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. 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: + +| 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 the Calendar question, the executor reads `calendar/events.json` under Calendar’s host directory through `calendar.events`. The model receives the service’s result; it does not open the file itself. Other app tools have narrower scopes: + +| App | Current data/tool boundary | +| --- | --- | +| News | `news.list`, `news.read` and `news.notify` | +| Mail | **Only `mail.notify`**; the UI’s read/send APIs are not agent tools | +| Photos, Maps, Camera, YouTube | Only their own `.notify`, publishing a shared notice card through [glance_notice.rs](../crates/shell/src/glance_notice.rs) | +| AI providers | No app agent | + +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:** this skips the owning app’s model and invokes its executor directly. For example, another app could call a shared Calendar tool only when all of these prerequisites hold: + +1. The tool has a declaration with `shareable: true` and an executable handler. +2. The caller has a grant. Script manifests request dotted names in `agent.tools`; native apps use their reviewed grants. `may_call` checks these rules, with explicit developer-mode exceptions. +3. For a script bundle, App Hub admission—the check that the host accepts the bundle—allows the name through `HostLimits.offered_tools`. +4. `Catalog::owner_of` can resolve the owner, so the relay can call that owner’s executor. + +The executor controls access to the receiving app’s data. Current owner resolution covers native namespaces, toolbox namespaces and `os.`; it does not discover arbitrary installed store apps. Default admission does not offer arbitrary names such as `mail.send`, and Mail does not currently implement that agent tool. A relay route alone cannot make it callable. + +**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 + +A peer is persisted identity and state. A **Tokio task** is an async computation scheduled on a runtime’s worker threads; waiting for I/O lets that worker run another ready task. A turn uses several tasks, and the peer survives their completion. + +Follow the direct “Ask Calendar” question across those boundaries: + +1. The Makepad UI submits a context request to Calendar’s broker. +2. The broker’s runtime sends `turn/start` through a shared kernel `Connection`; the kernel-service supervisor carries it across the transport. +3. octos spawns a turn orchestration task. It waits at a start barrier until the active-turn registry accepts it, then starts agent processing. +4. If the model calls `calendar.events`, its tool future waits while the broker and shell relay deliver the request to Calendar’s host service. The returned data lets the model continue; reply events travel back to the human context and wake the UI. + +These are scheduling boundaries, not a new thread or process for every peer. Use this table to locate their owners: + +| 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 | 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 | + +```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 and account is an identity rule. The number of tasks and worker threads follows the runtimes and active operations above. + +## 11. Tests and remaining implementation + +[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. + +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 +``` + +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. + +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 new file mode 100644 index 00000000..5344511c --- /dev/null +++ b/docs/architecture-walkthrough.zh-CN.md @@ -0,0 +1,289 @@ +# 代码导读:从应用窗口到 Agent 回合 + +[English](architecture-walkthrough.md) | 简体中文 + +本文沿着一条消息,阅读应用窗口、Shell、Agent 内核与工具执行器之间的调用。如果你了解 Rust,但刚接触 OctoSense 或 Agent,可以从这里开始。[架构参考](architecture.zh-CN.md)介绍整体设计,本文跟踪实现中的调用与所有权。依赖版本以 [Cargo.toml](../Cargo.toml) 和 [native-runtime.lock.json](../native-runtime.lock.json) 为准。ADR 记录设计决策,尚待实现的部分列在第 11 节。 + +全文使用同一个问题:**“我今天有哪些日程?”** 桌面用户可以让系统助手委派给 Calendar,也可以直接通过 “Ask Calendar” 提问。两条路线都可能调用 `calendar.events`,但答案返回不同的对话。这是说明调用关系的例子:需要已配置的内核/提供方和用户同意,是否调用工具由模型决定。 + +## 1. 先分清这些名称 + +| 名称 | 本文中的含义 | +| --- | --- | +| 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,有独立记录、工作目录,以及 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/blob/218b25d2460d64f843932f67d419467618464fb9/docs/CODE-WALKTHROUGH.md)、[App Hub](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/19bb52d402e80e89e085dea989615e3ec612d359/docs/CODE-WALKTHROUGH.md)、[Octoscript-Makepad](https://github.com/OctoSense-org/OctoScript-Makepad/blob/fb29b6b1cb6e16f38d99a8aef60431a9565dfd59/docs/architecture-walkthrough.md)、[octos](https://github.com/octos-org/octos/blob/82900bf149d3a53016c1c1492ffc075d2d4fb0ed/docs/octosense-integration-walkthrough.md)。这些链接指向已发布的文档版本;运行时版本仍由使用方的依赖锁定文件控制。 + +## 2. 从可执行入口读到应用宿主 + +先打开 [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 的 AppRegistry](../crates/shell/src/apps.rs) 与各产品的 `system-apps.json`: + +| 启动对象 | 代码路径 | 实际运行方式 | +| --- | --- | --- | +| 原生 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)。以下构建/启动配方 **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 +``` + +真实对话还需要在 AI providers 的宿主确认面板配置提供方、模型与凭据。`OCTOS_APP_CORE_BIN` 指定一个文件;此启动器不会搜索 `PATH`。自动 UI 工作使用产品 README 中的隐藏窗口方式。 + +脚本应用使用 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. 找到内核的所有者 + +依次阅读 [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` 选择桌面子进程(`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”,负责通过 Android bridge 执行允许的平台操作;系统 LLM 对话运行在 octos 中。 + +## 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。宿主通过 `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` 打开首次同意面板并等待可用的 peer slug(内核为该 peer 分配的标识符)。成功后系统 Agent 用 `peer_send_input` 提交任务;ask 调用只准备访问。首次同意由用户控制。 + +## 5. 一个应用 peer,两条对话通道 + +先读 [app-peers/src/contract.rs](../crates/app-peers/src/contract.rs),再读较大的 [broker.rs](../crates/app-peers/src/broker.rs): + +- `OctosAppService`:应用拿到的作用域助手句柄。 +- `OctosContext`:对话/请求句柄;`call(ContextOp, EventSink)` 启动操作;event sink 是接收进度、回复和完成事件(`ContextEvent`)的回调。 +- `ContextSpec`:宿主认证的账号、实例与已授权服务名。 +- `Broker`:将应用请求接到内核的 Shell 适配器,通过 `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 资格;运行还需要内核、用户同意及适用的有效账号。 + +原生进程客户端使用 [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`。 + +`card.os.news` 是 broker 的应用身份;内核的 peer slug 由 `peer/prepare` 返回,连同 peer session 和宿主凭据一起使用。Peer 按应用与账号区分:无账号应用使用 `device`,Mail 使用宿主报告的登录账号。`ensure_peer` 恢复记录的 peer,核对命名空间并注册工具,然后才运行回合。 + +在 Calendar 例子中,系统委派走系统通道,“Ask Calendar” 走用户通道。图中的**黑板(blackboard)**是内核保存 peer 工作与结果的共享记录,系统 Agent 用 `peer_gather` 读取它。 + +```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。 + +多个原生实例共享 peer 时,broker 的 `driver_of` / `take_over` 选择一个 broker 驱动系统通道输入队列,避免多个窗口重复执行 `peer/input`。用户 context 的工作可以与当前系统通道回合并发。 + +## 6. 用户在哪里提问,结果返回哪里 + +| 入口 | 实现与行为 | +| --- | --- | +| 系统助手面板,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;宿主核对卡片归属。 | + +随产品提供的 `.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`;脚本标签不能作为可信用户动作来匹配审批规则。 + +结构化工具结果回到发起它的应用回合。用户 context 的最终事件经其 event sink 回到对应界面;系统委派回合的结果写入 peer 黑板,由系统 Agent 获取并整理回答。 + +## 7. 从工具声明追到 Rust 执行器 + +阅读 [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. `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 尚无脚本工具执行器,会返回 unavailable。声明文件和准入检查分别描述、验证接口;真正操作需要执行器代码。 + +[host_tools/mod.rs](../crates/shell/src/host_tools/mod.rs) 将 broker 线程的调用放入 inbox,由 UI 事件循环泵送并排队回复: + +| 工具路线 | 执行边界 | +| --- | --- | +| 隔离应用,`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` 无法批准工具调用。 + +## 8. “访问应用数据”对应哪些存储 + +| 数据 | 应用 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` 读取宿主目录中的 `calendar/events.json`。模型收到服务结果,无需自行打开文件。其他应用的工具范围更窄: + +| 应用 | 当前数据/工具边界 | +| --- | --- | +| News | `news.list`、`news.read`、`news.notify` | +| Mail | **只有 `mail.notify`**;UI 的读信/发信 API 尚未开放为 Agent 工具 | +| Photos、Maps、Camera、YouTube | 仅各自的 `.notify`,经 [glance_notice.rs](../crates/shell/src/glance_notice.rs) 发布共享通知卡片 | +| AI providers | 没有应用 Agent | + +旧 AppCard 个人数据导入器不会自动同步当前 Mail 存储。 + +账号目录名使用 SHA-256 派生 tag,peer 记忆名称使用 broker 的 FNV 派生 tag;它们是不同的兼容标识。退出登录会暂停访问并保留数据;移除账号/卸载还会请求 `peer/purge`,忙碌时重试。恢复 peer 时,其已保存的工作目录不能悄悄改变。 + +## 9. 跨应用工作与求助 + +**委派任务:**系统 Agent 用 `peer_send_input` 请求现有应用 peer 工作,再获取结果。Shell 驱动该应用回合,peer 身份可以跨进程生命周期保留。 + +**直接调用另一应用的 API 工具:**这条路线直接调用所属应用的执行器,无需经过它的模型。例如,另一应用要调用可共享的 Calendar 工具,必须满足以下条件: + +1. 工具已有声明、`shareable: true` 和实际执行器。 +2. 调用方有授权。脚本 manifest 在 `agent.tools` 中请求带点的名称,原生应用使用审核过的授权;`may_call` 检查这些规则,显式开发者模式例外另行处理。 +3. 对脚本包,App Hub 准入(宿主接受应用包的检查)通过 `HostLimits.offered_tools` 允许该名称。 +4. `Catalog::owner_of` 能找到所属应用,relay 才能调用其执行器。 + +接收方应用的数据访问由执行器控制。当前 owner 解析覆盖原生命名空间、toolbox 和 `os.`,尚不支持发现任意已安装商店应用。默认准入未提供 `mail.send` 等任意名称,Mail 当前也未实现这个 Agent 工具;仅有 relay 路线不足以使它可调用。 + +**提问或使用系统设施:**应用 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 的实际执行模型 + +Peer 是持久身份与状态。**Tokio task** 是由 runtime 工作线程调度的异步计算;等待 I/O 时,工作线程可以运行其他就绪任务。一个回合会用到多个 task,peer 在它们结束后仍存在。 + +沿着直接发送给 “Ask Calendar” 的问题,依次跨过这些边界: + +1. Makepad UI 将 context 请求交给 Calendar 的 broker。 +2. Broker 的 runtime 经共享内核 `Connection` 发送 `turn/start`,由内核服务 supervisor 送入传输连接。 +3. octos spawn 回合编排 task;它先在启动屏障等待活跃回合注册成功,再开始 Agent 处理。 +4. 若模型调用 `calendar.events`,工具 future 等待 broker 与 Shell relay 将请求交给 Calendar 宿主服务。返回的数据让模型继续;回复事件经用户 context 返回并唤醒 UI。 + +这些是调度边界;每个 peer 并不各自创建线程或进程。下表列出各部分的所有者: + +| 层 | 实际执行模型 | 源码 | +| --- | --- | --- | +| 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 检查拒绝旧账号或连接的迟到回复。 + +Broker 同步 `bind` / `host_request` 会等待通道回复,不应在绘制回调中调用。不同 session 的异步模型 I/O 可重叠,同步文件工作仍走已有的工作线程边界。每应用/账号一个 peer 是身份规则;task 和线程数量由上表的 runtime 与活跃操作决定。 + +## 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)覆盖调用方、工具与审批边界;修改对话或执行路径时从这些测试开始。 + +在仓库根目录运行单元测试与脚本化连接器测试: + +```sh +cargo test --locked -p octosense-kernel -p octosense-app-peers \ + --features octosense-app-peers/octos-core,octosense-app-peers/ws +``` + +可选真实内核测试在缺少二进制环境变量时提前返回;将结果当作集成证据前,阅读 [app-peers 测试说明](../crates/app-peers/README.md)。可见 UI、真实提供方对话和设备行为需要分别运行。 + +尚待实现:应用包 `AGENT.md` 提示词加载、自动 triggers/skills、脚本实现的 Agent 工具分发,以及通用应用到系统 Agent 对话 RPC。围绕这些路径设计流程前,沿声明追到实际执行器。 diff --git a/docs/architecture.md b/docs/architecture.md index 29c1c3ed..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. It describes `main` on 2026-09-28 (OctoSense `ff40e9c`, which pins octos `5e7577f0`), read in the code. +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, 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 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,13 +172,13 @@ 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): - **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 @@ -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 | @@ -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..1d9b021b 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)。依赖版本以 [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 | 是什么 | 状态 | | --- | --- | --- | @@ -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 @@ -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,31 +426,32 @@ 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 自己的界面会显示变化,因为它们的数据变了。 | 规划中 | ## 代码与 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..b9d5ca84 --- /dev/null +++ b/phone/AGENTS.md @@ -0,0 +1,23 @@ +# Working on Home + +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/`; 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 52dfa3bb..2a3d5b54 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, 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). 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 @@ -239,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 693987a2..71c25141 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` 时才会链接。) @@ -136,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 4764192a..87606b73 100644 --- a/phone/android/README.md +++ b/phone/android/README.md @@ -55,17 +55,19 @@ 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 recipe.** For the Home/Bridge pair and 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 +85,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..9bff0ecf 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..c725e684 --- /dev/null +++ b/rom/AGENTS.md @@ -0,0 +1,23 @@ +# Working on the ROM + +Follow the [repository rules](../AGENTS.md), +[Home build contract](docs/home-build.md) and +[product walkthrough](../desktop/docs/code-walkthrough.md). + +- 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 01b964f8..83f36fcc 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, 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 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..97d84a89 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,并加上具有系统权限的系统侧组件。