From a50c607ebb369cbef85b1f899ead40f59c4cb77a Mon Sep 17 00:00:00 2001 From: Edward Tan Date: Thu, 1 Oct 2026 19:04:52 -0700 Subject: [PATCH 1/3] docs(ai-services): contained apps' assistant is behind consent, not off docs/ai-services.md and its Chinese twin still described the contained apps' octos service as it was before #184: - the gate is off by default and needs OCTOSENSE_CONTAINED_APPS=1; the code's default is first-use consent (contained_gate_from), with 1 the developer override that asks nobody and 0 off; - a contained peer's tool approvals are declined; the broker hands them to the shell's approval router, and only a host without one declines; - octos.turn.start takes only text; it also takes trigger and from; - nothing in the shells runs an app's agent; since #184 an app that declares one, declares octos.*, or ships tools.json gets a prepared peer with its tools and the "Ask " panel; - the News bundle does not declare `news` yet; it does, and reads from it when host.has("news"). --- docs/ai-services.md | 14 +++++++------- docs/ai-services.zh-CN.md | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/ai-services.md b/docs/ai-services.md index caba9c00..a40c426a 100644 --- a/docs/ai-services.md +++ b/docs/ai-services.md @@ -27,7 +27,7 @@ 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, owned by the system agent | Works today, for native modules (Rinx) and, behind a switch, contained script apps | [`crates/app-peers`](../crates/app-peers/README.md), [Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | | AppCard ("Ask anything") on the shell's kernel | Works today, opt-in (`--features app-appcard`), not shipped | [`apps/appcard`](../apps/appcard) | -| A contained script app (system or store) asking the assistant | Works where the shell hosts a kernel ([#106](https://github.com/OctoSense-org/OctoSense/pull/106)): the `octos` host service gives each app its own peer (`card.`), while `Policy::contained_apps` is on (**off by default**; `OCTOSENSE_CONTAINED_APPS=1`) and after the person allows the app's agent at first use ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)). Tool approvals the peer raises are still declined. `llm` stays provider management for `os.*` apps only | [below](#contained-script-apps-system-and-store) | +| A contained script app (system or store) asking the assistant | Works where the shell hosts a kernel ([#106](https://github.com/OctoSense-org/OctoSense/pull/106)): the `octos` host service gives each app its own peer (`card.`), once the person allows the app's agent at first use ([#120](https://github.com/OctoSense-org/OctoSense/pull/120), the default; `OCTOSENSE_CONTAINED_APPS=1` asks nobody, `0` turns the service off). Tool approvals the peer raises go to the shell's approval router and its sheets. `llm` stays provider management for `os.*` apps only | [below](#contained-script-apps-system-and-store) | | One-shot model calls for contained apps (`model`, `model.complete`) | Works today ([#95](https://github.com/OctoSense-org/OctoSense/pull/95)): registered by `crates/ai-host` with the `llm` service, for apps granted `model` ([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24), in the shells' App Hub pin) | [below](#contained-script-apps-system-and-store) | | News data service (`news`, no model) | Merged ([#69](https://github.com/OctoSense-org/OctoSense/pull/69)); answers `os.*` apps only | [`apps/news/host-service`](../apps/news/host-service/README.md) | | `glance.publish`: L0 cards on the glance screen | Merged ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)); contained apps granted the `glance` capability publish ([#86](https://github.com/OctoSense-org/OctoSense/pull/86)). In progress: `sys.digest` sources ([#87](https://github.com/OctoSense-org/OctoSense/pull/87), draft) | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | @@ -105,7 +105,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 at all. `Policy::shipped()` grants only `rinx` the four services, and turns the contained apps' switch (`Policy::contained_apps`) on only with `OCTOSENSE_CONTAINED_APPS=1`. The person's per-app switch is **first-use consent** ([#120](https://github.com/OctoSense-org/OctoSense/pull/120), `crates/shell/src/approvals/consent.rs`): the first time an app asks for its agent the shell shows what it may read and use and where the model runs, and **Settings → Assistant → Approvals** lists every app's agent with an off switch ([architecture § Approvals](architecture.md#5-approvals)). +The host **policy** decides which native modules may use the assistant, by exact `octos.*` service name, and whether contained apps get the `octos` service at all. `Policy::shipped()` grants only `rinx` the four services, and puts contained apps behind first-use consent (`ContainedGate::Consent`, `contained_gate_from` in `crates/ai-host/src/lib.rs`): `OCTOSENSE_CONTAINED_APPS=1` is the developer override that asks nobody, and `0` turns the `octos` service off for every app. The person's per-app switch is **first-use consent** ([#120](https://github.com/OctoSense-org/OctoSense/pull/120), `crates/shell/src/approvals/consent.rs`): the first time an app asks for its agent the shell shows what it may read and use and where the model runs, and **Settings → Assistant → Approvals** lists every app's agent with an off switch ([architecture § Approvals](architecture.md#5-approvals)). ### `crates/app-peers`: host-owned app peers @@ -171,10 +171,10 @@ A script app runs in App Hub's Card runner and reaches the shell only through `h | --- | --- | --- | | `mail` | any app granted `mail` | Mail accounts the person signs in to on the host's sheet | | `llm` | `os.*` apps only | Managing the assistant's providers (`llm.providers`, `llm.add_provider`, `llm.test`, `llm.import_qr`, …); **no prompt or completion method** | -| `news` | `os.*` apps only (`may_call` in `apps/news/host-service/src/lib.rs`) | News's data service (feeds, ledger, `news.list`, `news.read`, …); no model. The shells' App Hub pin knows the `news` capability, but the News bundle does not declare it yet (`apps/news/bundle/manifest.json`), so it still fetches on its own | +| `news` | `os.*` apps only (`may_call` in `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")` | | `glance` | apps granted the `glance` capability ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) | Publishing L0 cards to the glance screen, under the app's own id (`crates/shell/src/glance.rs`) | | `model` | apps granted the `model` capability ([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24)) | One-shot `model.complete {task, input, schema, class?, allow_urls?}` and `model.budget` ([#95](https://github.com/OctoSense-org/OctoSense/pull/95), `apps/ai-providers/host-service/src/complete/`, registered in `crates/ai-host/src/lib.rs`): `class` `fast` or `strong`; the host picks the model from the person's providers, validates the reply against the schema, refuses URLs unless asked, keeps a per-app daily budget; no tools, memory or history, and the app never sees a key | -| `octos` | any app whose manifest declares the exact `octos.*` names, while the shell hosts a kernel, `Policy::contained_apps` is on (**off by default**; set `OCTOSENSE_CONTAINED_APPS=1` to try it) and the person allowed the app's agent at first use (`consent_for_contained`, [#120](https://github.com/OctoSense-org/OctoSense/pull/120)) | The assistant, through the app's own host-owned peer `card.` (`crates/ai-host/src/contained.rs`, [#106](https://github.com/OctoSense-org/OctoSense/pull/106)): the four `octos.*` calls with Rinx's argument rules (`octos.turn.start` takes only `text`, non-blank, at most 32 KiB; the others take `{}`). Tool approvals the peer raises are declined and listed in the reply's `denied_approvals` (the shell's approval router takes the kernel's `host_tool` approvals since #145, but not these other approvals of a contained app's peer); in developer mode they are answered for the apps it covers (`crates/app-peers/src/host_approvals.rs`). Replies over 2 MiB are refused | +| `octos` | any app whose manifest declares the exact `octos.*` names, while the shell hosts a kernel, once the person allowed the app's agent at first use (`consent_for_contained`, [#120](https://github.com/OctoSense-org/OctoSense/pull/120); `OCTOSENSE_CONTAINED_APPS=1` asks nobody, `0` turns it off) | The assistant, through the app's own host-owned peer `card.` (`crates/ai-host/src/contained.rs`, [#106](https://github.com/OctoSense-org/OctoSense/pull/106)): the four `octos.*` calls (`octos.turn.start` takes `text`, non-blank, at most 32 KiB, and optionally `trigger`, one of `person`, `app` or `incoming`, with `from`; the others take `{}`). Tool approvals the peer raises go to the shell's approval router and its sheets (ADR 0004 §8); only a host without a router declines them, listing them in the reply's `denied_approvals`. In developer mode they are answered for the apps it covers (`crates/app-peers/src/host_approvals.rs`). Replies over 2 MiB are refused | So a contained app, store or system, reaches the assistant only through `octos.*`, in a shell that hosts a kernel. What it hears: @@ -183,7 +183,7 @@ So a contained app, store or system, reaches the assistant only through `octos.* | a family the manifest did not grant | `r.error`: `this app was not granted "", which "" needs` (at once, from the isolate) | | `octos.turn.start {text}`, granted, kernel and provider configured | `r.data`: `{turn_id, text}`, the reply of the app's peer | | `octos.*` with arguments beyond the rules | `r.error`: `Unsupported Octos arguments`, or `Provide text (at most 32 KiB)` | -| `octos.*` with `Policy::contained_apps` off | `r.error`: `The assistant is turned off for apps on this device` | +| `octos.*` with the assistant turned off for apps (`OCTOSENSE_CONTAINED_APPS=0`) | `r.error`: `The assistant is turned off for apps on this device` | | `octos.*` before the person allowed the app's agent | `r.error`: `Waiting for the person to allow this app's agent (OctoSense asks the first time)`, and the shell shows its first-use sheet (read in `contained.rs` and `approvals/mod.rs`; **unverified** in a running shell) | | `octos.*` on a desktop without `OCTOS_APP_CORE_BIN` | `r.error`: `no octos kernel: no kernel binary configured (OCTOS_APP_CORE_BIN)` | | `octos.*` in a build that links no kernel (iOS) | `r.error`: `no service answers "octos" on this device` (**unverified**) | @@ -192,7 +192,7 @@ So a contained app, store or system, reaches the assistant only through `octos.* The first row, the `llm` row and the `card-host` row were run in `card-host` (App Hub `362d832`) on 2026-09-27. The reply, the unsupported-arguments answer and the missing-kernel answer were run on macOS on 2026-09-28 in a release desktop with hidden windows, through a system app declaring `octos.session.open` and `octos.turn.start` opened from the launcher; with a kernel built at the then-pinned octos `7bec0918` and the person's provider, the reply came from the peer `card.`, whose memory namespace `app/card./…` appeared in the kernel's data. The text-length and switch-off answers are covered by `cargo test -p octosense-ai-host`, through the same dispatch. OctoScript-App-Design-Flow's [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) has the example app and the argument and answer shapes of the four `octos.*` calls as Rinx serves them. -The manifest's `agent` field (a permission profile, generic tools, iteration and token limits) is admitted and clamped by App Hub, but **nothing in the shells runs an agent for it**, and Rinx refuses to import a bundle that declares one. An app must not depend on it. +The manifest's `agent` field (a permission profile, generic tools, iteration and token limits) is admitted and clamped by App Hub. Since [#184](https://github.com/OctoSense-org/OctoSense/pull/184), an app that declares one, declares `octos.*`, or ships `tools.json` has an agent: once the person allows it, the shell prepares its peer `card.` with the bundle's tools (`crates/shell/src/agents.rs`), and the person can talk to it in the shell's "Ask " panel. The shell keeps the generic tools App Hub admits (`ask_user_question`), but does not apply the profile or the limits, or install `AGENT.md` or skills, yet. Rinx refuses to import a bundle that declares an agent. ## Planned: event-driven app agents (ADR 0002) @@ -240,7 +240,7 @@ The tracking issue is [#68](https://github.com/OctoSense-org/OctoSense/issues/68 The log says `octos: kernel service ready (starts on first use), core dir …`. Without `OCTOS_APP_CORE_BIN` it says there is no kernel, and AI providers still saves providers. 3. Open **Start → Settings → AI providers**, add a model (family, model, route, key, **Test connection**, save). The profile is `$T/octos-home/.octos/profiles/_main.json`; with the file vault the key is in it, so delete `$T` afterwards. -4. Use the assistant through a consumer: Rinx (linked by default and in-process; open it from the launcher; sign in to Matrix, allow its agent on the first-use sheet, then use its assistant), or AppCard (`--features app-appcard`). A contained app reaches it through the `octos` host service ([above](#contained-script-apps-system-and-store)); add `OCTOSENSE_CONTAINED_APPS=1` to the command in step 2 and allow the app's agent when the shell asks. +4. Use the assistant through a consumer: Rinx (linked by default and in-process; open it from the launcher; sign in to Matrix, allow its agent on the first-use sheet, then use its assistant), or AppCard (`--features app-appcard`). A contained app reaches it through the `octos` host service ([above](#contained-script-apps-system-and-store)); allow the app's agent when the shell asks the first time (or add `OCTOSENSE_CONTAINED_APPS=1` to the command in step 2 to skip the question for every app). **Hidden windows.** Add `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=` to drive the shell over the remote bridge without taking the screen ([desktop README § Remote-control bridge](../desktop/README.md#remote-control-bridge)). `desktop/scripts/ai_providers_remote.sh` runs AI providers end to end this way with fake keys and outbound HTTPS denied, and `desktop/scripts/glance_remote.sh` does the same for the glance panel. diff --git a/docs/ai-services.zh-CN.md b/docs/ai-services.zh-CN.md index 7f44059d..932c452f 100644 --- a/docs/ai-services.zh-CN.md +++ b/docs/ai-services.zh-CN.md @@ -27,7 +27,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)):`octos` 宿主服务为每个应用分配自己的 peer(`card.<应用 id>`),前提是 `Policy::contained_apps` 为开(**默认关闭**;`OCTOSENSE_CONTAINED_APPS=1`),且用户在首次使用时允许了该应用的 Agent([#120](https://github.com/OctoSense-org/OctoSense/pull/120))。peer 发起的工具审批仍会被拒绝。`llm` 仍是只供 `os.*` 应用使用的提供方管理服务 | [见下文](#隔离运行的脚本应用系统应用和商店应用) | +| 隔离运行的脚本应用(系统应用或商店应用)向助手提问 | 在托管了内核的 Shell 中可用([#106](https://github.com/OctoSense-org/OctoSense/pull/106)):`octos` 宿主服务为每个应用分配自己的 peer(`card.<应用 id>`),前提是用户在首次使用时允许了该应用的 Agent([#120](https://github.com/OctoSense-org/OctoSense/pull/120),默认行为;`OCTOSENSE_CONTAINED_APPS=1` 不询问任何人,`0` 关闭该服务)。peer 发起的工具审批交给 Shell 的审批路由和它的面板处理。`llm` 仍是只供 `os.*` 应用使用的提供方管理服务 | [见下文](#隔离运行的脚本应用系统应用和商店应用) | | 供隔离应用使用的一次性模型调用(`model`,`model.complete`) | 目前可用([#95](https://github.com/OctoSense-org/OctoSense/pull/95)):由 `crates/ai-host` 与 `llm` 服务一同注册,供获得 `model` 权限的应用使用([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24),已在 Shell 锁定的 App Hub 中) | [见下文](#隔离运行的脚本应用系统应用和商店应用) | | News 数据服务(`news`,不使用模型) | 已合入([#69](https://github.com/OctoSense-org/OctoSense/pull/69));只响应 `os.*` 应用 | [`apps/news/host-service`](../apps/news/host-service/README.md) | | `glance.publish`:glance 屏幕上的 L0 卡片 | 已合入([#72](https://github.com/OctoSense-org/OctoSense/pull/72));获得 `glance` 权限的隔离应用可以发布([#86](https://github.com/OctoSense-org/OctoSense/pull/86))。进行中:`sys.digest` 数据源([#87](https://github.com/OctoSense-org/OctoSense/pull/87),草稿) | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | @@ -105,7 +105,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`,并且只有设置 `OCTOSENSE_CONTAINED_APPS=1` 时才打开隔离应用的开关(`Policy::contained_apps`)。用户按应用的开关是**首次使用同意**([#120](https://github.com/OctoSense-org/OctoSense/pull/120),`crates/shell/src/approvals/consent.rs`):应用第一次请求它的 Agent 时,Shell 显示它可以读取和使用什么、模型在哪里运行;**设置 → 助手 → 审批**列出每个应用的 Agent,并带有关闭开关([架构 § 审批](architecture.zh-CN.md#5-审批))。 +宿主**策略**按精确的 `octos.*` 服务名决定哪些原生模块可以使用助手,以及隔离应用是否能使用 `octos` 服务。`Policy::shipped()` 只把这四个服务授予 `rinx`,并让隔离应用经过首次使用同意(`ContainedGate::Consent`,`crates/ai-host/src/lib.rs` 中的 `contained_gate_from`):`OCTOSENSE_CONTAINED_APPS=1` 是不询问任何人的开发者覆盖开关,`0` 为所有应用关闭 `octos` 服务。用户按应用的开关是**首次使用同意**([#120](https://github.com/OctoSense-org/OctoSense/pull/120),`crates/shell/src/approvals/consent.rs`):应用第一次请求它的 Agent 时,Shell 显示它可以读取和使用什么、模型在哪里运行;**设置 → 助手 → 审批**列出每个应用的 Agent,并带有关闭开关([架构 § 审批](architecture.zh-CN.md#5-审批))。 ### `crates/app-peers`:宿主拥有的应用 peer @@ -171,10 +171,10 @@ flowchart TB | --- | --- | --- | | `mail` | 获得 `mail` 授权的任何应用 | 用户在宿主面板上登录的邮件账号 | | `llm` | 仅 `os.*` 应用 | 管理助手的提供方(`llm.providers`、`llm.add_provider`、`llm.test`、`llm.import_qr` 等);**没有提示词或补全方法** | -| `news` | 仅 `os.*` 应用(`apps/news/host-service/src/lib.rs` 中的 `may_call`) | News 的数据服务(订阅源、已读记录、`news.list`、`news.read` 等),不使用模型。Shell 锁定的 App Hub 已认识 `news` 权限,但 News 应用包还没有声明它(`apps/news/bundle/manifest.json`),所以仍自己抓取 | +| `news` | 仅 `os.*` 应用(`apps/news/host-service/src/lib.rs` 中的 `may_call`) | News 的数据服务(订阅源、已读记录、`news.list`、`news.read` 等),不使用模型。News 应用包声明了它(`apps/news/bundle/manifest.json`),并在 `host.has("news")` 时从中读取 | | `glance` | 获得 `glance` 权限的应用([#86](https://github.com/OctoSense-org/OctoSense/pull/86)、[App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) | 以应用自己的 id 向 glance 屏幕发布 L0 卡片(`crates/shell/src/glance.rs`) | | `model` | 获得 `model` 权限的应用([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24)) | 一次性的 `model.complete {task, input, schema, class?, allow_urls?}` 和 `model.budget`([#95](https://github.com/OctoSense-org/OctoSense/pull/95),`apps/ai-providers/host-service/src/complete/`,在 `crates/ai-host/src/lib.rs` 中注册):`class` 为 `fast` 或 `strong`;宿主从用户的提供方中挑选模型,按 schema 校验回复,除非请求否则拒绝含 URL 的回复,按应用管理每日预算;没有工具、记忆和历史,应用也看不到任何密钥 | -| `octos` | manifest 声明了确切 `octos.*` 名称的任何应用;前提是 Shell 托管了内核、`Policy::contained_apps` 为开(**默认关闭**;设置 `OCTOSENSE_CONTAINED_APPS=1` 可试用),且用户在首次使用时允许了该应用的 Agent(`consent_for_contained`,[#120](https://github.com/OctoSense-org/OctoSense/pull/120)) | 助手:经应用自己的、由宿主拥有的 peer `card.<应用 id>`(`crates/ai-host/src/contained.rs`,[#106](https://github.com/OctoSense-org/OctoSense/pull/106))。四个 `octos.*` 调用沿用 Rinx 的参数规则(`octos.turn.start` 只接受 `text`,非空白、最多 32 KiB;其余只接受 `{}`)。peer 发起的工具审批会被拒绝并列在回复的 `denied_approvals` 中(在 octos#2567 之前,Shell 的审批路由不接收内核审批);开发者模式下由它为覆盖的应用作答(`crates/app-peers/src/host_approvals.rs`)。超过 2 MiB 的回复会被拒绝 | +| `octos` | manifest 声明了确切 `octos.*` 名称的任何应用;前提是 Shell 托管了内核,且用户在首次使用时允许了该应用的 Agent(`consent_for_contained`,[#120](https://github.com/OctoSense-org/OctoSense/pull/120);`OCTOSENSE_CONTAINED_APPS=1` 不询问任何人,`0` 关闭它) | 助手:经应用自己的、由宿主拥有的 peer `card.<应用 id>`(`crates/ai-host/src/contained.rs`,[#106](https://github.com/OctoSense-org/OctoSense/pull/106))。四个 `octos.*` 调用(`octos.turn.start` 接受 `text`,非空白、最多 32 KiB,并可选 `trigger`,取 `person`、`app` 或 `incoming` 之一,以及 `from`;其余只接受 `{}`)。peer 发起的工具审批交给 Shell 的审批路由和它的面板(ADR 0004 §8);只有没有审批路由的宿主才会拒绝它们,并列在回复的 `denied_approvals` 中。开发者模式下由它为覆盖的应用作答(`crates/app-peers/src/host_approvals.rs`)。超过 2 MiB 的回复会被拒绝 | 因此,隔离运行的应用(商店应用或系统应用)只能通过 `octos.*` 使用助手,且需要 Shell 托管了内核。它会收到: @@ -183,7 +183,7 @@ flowchart TB | manifest 未授予的 family | `r.error`:`this app was not granted "", which "" needs`(由隔离环境立即返回) | | 已获授权的 `octos.turn.start {text}`,内核与提供方已配置 | `r.data`:`{turn_id, text}`,即应用 peer 的回复 | | 参数超出规则的 `octos.*` | `r.error`:`Unsupported Octos arguments` 或 `Provide text (at most 32 KiB)` | -| `Policy::contained_apps` 为关时的 `octos.*` | `r.error`:`The assistant is turned off for apps on this device` | +| 设备为应用关闭了助手时(`OCTOSENSE_CONTAINED_APPS=0`)的 `octos.*` | `r.error`:`The assistant is turned off for apps on this device` | | 用户尚未允许该应用的 Agent 时的 `octos.*` | `r.error`:`Waiting for the person to allow this app's agent (OctoSense asks the first time)`,同时 Shell 显示首次使用面板(在 `contained.rs` 和 `approvals/mod.rs` 中读到;未在运行的 Shell 中验证,**unverified**) | | 在未设置 `OCTOS_APP_CORE_BIN` 的桌面端调用 `octos.*` | `r.error`:`no octos kernel: no kernel binary configured (OCTOS_APP_CORE_BIN)` | | 在不链接内核的构建(iOS)中调用 `octos.*` | `r.error`:`no service answers "octos" on this device`(**未验证**) | @@ -192,7 +192,7 @@ flowchart TB 第一行、`llm` 一行和 `card-host` 一行已于 2026-09-27 在 `card-host`(App Hub `362d832`)中运行验证。回复、参数不合规的返回和缺少内核的返回已于 2026-09-28 在 macOS 上运行验证:release 版桌面端、隐藏窗口,经启动器打开一个声明了 `octos.session.open` 和 `octos.turn.start` 的系统应用;使用按当时锁定的 octos `7bec0918` 构建的内核和用户自己的提供方时,回复来自 peer `card.<应用 id>`,内核数据中出现了它的记忆命名空间 `app/card.<应用 id>/…`。文本长度和开关关闭的返回由 `cargo test -p octosense-ai-host` 覆盖,走的是同一个分发函数。OctoScript-App-Design-Flow 的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 给出了示例应用,以及 Rinx 提供的四个 `octos.*` 调用的参数和返回形状。 -manifest 的 `agent` 字段(权限档位、通用工具、迭代和 token 上限)会被 App Hub 接受并按上限裁剪,但 **Shell 中没有任何东西为它运行 Agent**,Rinx 也会拒绝导入声明了它的应用包。应用不能依赖它。 +manifest 的 `agent` 字段(权限档位、通用工具、迭代和 token 上限)会被 App Hub 接受并按上限裁剪。自 [#184](https://github.com/OctoSense-org/OctoSense/pull/184) 起,声明了它、声明了 `octos.*` 或附带 `tools.json` 的应用都有 Agent:用户允许后,Shell 用应用包中的工具为它准备 peer `card.<应用 id>`(`crates/shell/src/agents.rs`),用户可以在 Shell 的“Ask ”面板中与它对话。Shell 保留 App Hub 接受的通用工具(`ask_user_question`),但还不应用权限档位和上限,也不安装 `AGENT.md` 或技能。Rinx 会拒绝导入声明了 Agent 的应用包。 ## 规划中:事件驱动的应用 Agent(ADR 0002) @@ -240,7 +240,7 @@ manifest 的 `agent` 字段(权限档位、通用工具、迭代和 token 上 日志中会出现 `octos: kernel service ready (starts on first use), core dir …`。没有 `OCTOS_APP_CORE_BIN` 时日志会说明没有内核,AI providers 仍会保存提供方。 3. 打开 **Start → Settings → AI providers**,添加一个模型(family、模型、路由、密钥、**Test connection**、保存)。配置文件是 `$T/octos-home/.octos/profiles/_main.json`;使用文件密钥库时密钥就在其中,用完后请删除 `$T`。 -4. 通过某个使用者来使用助手:Rinx(默认链接并在进程内运行;从启动器打开它;登录 Matrix,在首次使用面板上允许它的 Agent,然后使用它的助手),或 AppCard(`--features app-appcard`)。隔离运行的应用通过 `octos` 宿主服务访问它([见上文](#隔离运行的脚本应用系统应用和商店应用));在第 2 步的命令中加上 `OCTOSENSE_CONTAINED_APPS=1`,并在 Shell 询问时允许该应用的 Agent。 +4. 通过某个使用者来使用助手:Rinx(默认链接并在进程内运行;从启动器打开它;登录 Matrix,在首次使用面板上允许它的 Agent,然后使用它的助手),或 AppCard(`--features app-appcard`)。隔离运行的应用通过 `octos` 宿主服务访问它([见上文](#隔离运行的脚本应用系统应用和商店应用));在 Shell 第一次询问时允许该应用的 Agent(或在第 2 步的命令中加上 `OCTOSENSE_CONTAINED_APPS=1`,对所有应用跳过这个询问)。 **隐藏窗口。** 加上 `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=`,即可通过远程控制桥操作 Shell 而不占用屏幕([桌面端 README § Remote-control bridge](../desktop/README.md#remote-control-bridge))。`desktop/scripts/ai_providers_remote.sh` 以这种方式端到端运行 AI providers,使用假密钥并禁止出站 HTTPS;`desktop/scripts/glance_remote.sh` 对 glance 面板做同样的事。 From 3c25369b6015fbb980c086806b26db6198125960 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:38:37 -0700 Subject: [PATCH 2/3] docs: clarify walkthroughs for junior Rust readers --- docs/ai-services.md | 60 ++++++++++++++++++++++++------------ docs/ai-services.zh-CN.md | 64 ++++++++++++++++++++++++++------------- 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/docs/ai-services.md b/docs/ai-services.md index a40c426a..949f43ad 100644 --- a/docs/ai-services.md +++ b/docs/ai-services.md @@ -25,16 +25,16 @@ For the whole system around it (processes per platform, agents, protocols, tools | One octos kernel per shell process, started on first use, restarted after a provider change | Works today (desktop with `OCTOS_APP_CORE_BIN`, Android, OpenHarmony; none on iOS) | [`crates/kernel`](../crates/kernel/README.md) | | AI providers: the person's model providers and keys, keys only on host sheets | Works today | [`apps/ai-providers`](../apps/ai-providers/host-service/README.md) | | The shell's AI entry point (`start`, policy, per-instance offer, QR import) | Works today | [`crates/ai-host`](../crates/ai-host/README.md) | -| Host-owned app peers: one octos peer per granted app, owned by the system agent | Works today, for native modules (Rinx) and, behind a switch, contained script apps | [`crates/app-peers`](../crates/app-peers/README.md), [Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | +| Host-owned app peers: one octos peer per granted app/account, owned by the system agent | Implemented for native modules (Rinx) and contained script apps after per-app consent | [`crates/app-peers`](../crates/app-peers/README.md), [Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | | AppCard ("Ask anything") on the shell's kernel | Works today, opt-in (`--features app-appcard`), not shipped | [`apps/appcard`](../apps/appcard) | -| A contained script app (system or store) asking the assistant | Works where the shell hosts a kernel ([#106](https://github.com/OctoSense-org/OctoSense/pull/106)): the `octos` host service gives each app its own peer (`card.`), once the person allows the app's agent at first use ([#120](https://github.com/OctoSense-org/OctoSense/pull/120), the default; `OCTOSENSE_CONTAINED_APPS=1` asks nobody, `0` turns the service off). Tool approvals the peer raises go to the shell's approval router and its sheets. `llm` stays provider management for `os.*` apps only | [below](#contained-script-apps-system-and-store) | +| 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) | | One-shot model calls for contained apps (`model`, `model.complete`) | Works today ([#95](https://github.com/OctoSense-org/OctoSense/pull/95)): registered by `crates/ai-host` with the `llm` service, for apps granted `model` ([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24), in the shells' App Hub pin) | [below](#contained-script-apps-system-and-store) | | News data service (`news`, no model) | Merged ([#69](https://github.com/OctoSense-org/OctoSense/pull/69)); answers `os.*` apps only | [`apps/news/host-service`](../apps/news/host-service/README.md) | -| `glance.publish`: L0 cards on the glance screen | Merged ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)); contained apps granted the `glance` capability publish ([#86](https://github.com/OctoSense-org/OctoSense/pull/86)). In progress: `sys.digest` sources ([#87](https://github.com/OctoSense-org/OctoSense/pull/87), draft) | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | +| `glance.publish`: L0/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) | | Native apps declared once (`native-apps.json`), hosting per target; the Terminal a system app in its own process on the desktop | Works today ([#113](https://github.com/OctoSense-org/OctoSense/pull/113)) | [architecture § Native apps](architecture.md#native-apps-in-process-or-their-own-process) | -| An app's own agent: `tools.json`, `AGENT.md`, skills, model requirements, triggers | Planned ([ADR 0002](adr/0002-event-driven-app-agents.md), Proposed). App Hub admits the files ([App-Hub#18](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/18)); no shell runs them. The kernel side is merged ([octos#2567](https://github.com/octos-org/octos/pull/2567), in the pin), and the shell registers each peer's tools and relays its calls ([#145](https://github.com/OctoSense-org/OctoSense/pull/145)), but no app declares `tools.json` yet, so every peer registers an empty set | [below](#planned-event-driven-app-agents-adr-0002) | +| An app's own agent: declarations versus execution | `tools.json`, generic-tool grants, peers and host-service executors are implemented for News/Mail/Calendar/Photos/Maps/Camera/YouTube. `AGENT.md` prompt loading, bundle skills/model selection and automatic triggers remain gaps | [below](#planned-event-driven-app-agents-adr-0002) | | Native apps in their own process reaching their agent (the peer link, ADR 0004 §5) | Built, no user yet. Makepad's client side ([OctoSense-org/makepad#54](https://github.com/OctoSense-org/makepad/pull/54), `makepad_ai_services::peer`) and the shell side ([#130](https://github.com/OctoSense-org/OctoSense/pull/130), `crates/shell/src/peer_link/`) are merged; no process app is granted an agent yet (the Terminal, the only process app, declares none) | [architecture § An app and its own agent](architecture.md#an-app-and-its-own-agent) | ## Architecture @@ -105,7 +105,21 @@ It is a contained script app like any other; the privileged half is the **`llm` [`crates/ai-host`](../crates/ai-host/README.md) (`octosense-ai-host`) is what both shells call: `start(Host::platform(data_dir))` at startup (configures the kernel, installs the host policy, registers `llm` with the platform's QR import), `handle_event` every event, `offer(module, scope)` / `finish()` around a native module's `create`, and `shutdown()`. -The host **policy** decides which native modules may use the assistant, by exact `octos.*` service name, and whether contained apps get the `octos` service at all. `Policy::shipped()` grants only `rinx` the four services, and puts contained apps behind first-use consent (`ContainedGate::Consent`, `contained_gate_from` in `crates/ai-host/src/lib.rs`): `OCTOSENSE_CONTAINED_APPS=1` is the developer override that asks nobody, and `0` turns the `octos` service off for every app. The person's per-app switch is **first-use consent** ([#120](https://github.com/OctoSense-org/OctoSense/pull/120), `crates/shell/src/approvals/consent.rs`): the first time an app asks for its agent the shell shows what it may read and use and where the model runs, and **Settings → Assistant → Approvals** lists every app's agent with an off switch ([architecture § Approvals](architecture.md#5-approvals)). +The host **policy** 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. + +#### Contained-app consent + +Contained apps use first-use consent by default. The environment variable `OCTOSENSE_CONTAINED_APPS` controls this policy: + +| 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. | +| `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. + +The policy is selected by `contained_gate_from` in [`crates/ai-host/src/lib.rs`](../crates/ai-host/src/lib.rs). Per-app consent is handled by [`crates/shell/src/approvals/consent.rs`](../crates/shell/src/approvals/consent.rs) ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)); see [architecture § Approvals](architecture.md#5-approvals). ### `crates/app-peers`: host-owned app peers @@ -174,7 +188,13 @@ A script app runs in App Hub's Card runner and reaches the shell only through `h | `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")` | | `glance` | apps granted the `glance` capability ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) | Publishing L0 cards to the glance screen, under the app's own id (`crates/shell/src/glance.rs`) | | `model` | apps granted the `model` capability ([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24)) | One-shot `model.complete {task, input, schema, class?, allow_urls?}` and `model.budget` ([#95](https://github.com/OctoSense-org/OctoSense/pull/95), `apps/ai-providers/host-service/src/complete/`, registered in `crates/ai-host/src/lib.rs`): `class` `fast` or `strong`; the host picks the model from the person's providers, validates the reply against the schema, refuses URLs unless asked, keeps a per-app daily budget; no tools, memory or history, and the app never sees a key | -| `octos` | any app whose manifest declares the exact `octos.*` names, while the shell hosts a kernel, once the person allowed the app's agent at first use (`consent_for_contained`, [#120](https://github.com/OctoSense-org/OctoSense/pull/120); `OCTOSENSE_CONTAINED_APPS=1` asks nobody, `0` turns it off) | The assistant, through the app's own host-owned peer `card.` (`crates/ai-host/src/contained.rs`, [#106](https://github.com/OctoSense-org/OctoSense/pull/106)): the four `octos.*` calls (`octos.turn.start` takes `text`, non-blank, at most 32 KiB, and optionally `trigger`, one of `person`, `app` or `incoming`, with `from`; the others take `{}`). Tool approvals the peer raises go to the shell's approval router and its sheets (ADR 0004 §8); only a host without a router declines them, listing them in the reply's `denied_approvals`. In developer mode they are answered for the apps it covers (`crates/app-peers/src/host_approvals.rs`). Replies over 2 MiB are refused | +| `octos` | 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: + +- **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). +- **Replies.** The host refuses replies larger than 2 MiB. The response table below lists successful calls and common errors. So a contained app, store or system, reaches the assistant only through `octos.*`, in a shell that hosts a kernel. What it hears: @@ -192,25 +212,27 @@ So a contained app, store or system, reaches the assistant only through `octos.* The first row, the `llm` row and the `card-host` row were run in `card-host` (App Hub `362d832`) on 2026-09-27. The reply, the unsupported-arguments answer and the missing-kernel answer were run on macOS on 2026-09-28 in a release desktop with hidden windows, through a system app declaring `octos.session.open` and `octos.turn.start` opened from the launcher; with a kernel built at the then-pinned octos `7bec0918` and the person's provider, the reply came from the peer `card.`, whose memory namespace `app/card./…` appeared in the kernel's data. The text-length and switch-off answers are covered by `cargo test -p octosense-ai-host`, through the same dispatch. OctoScript-App-Design-Flow's [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) has the example app and the argument and answer shapes of the four `octos.*` calls as Rinx serves them. -The manifest's `agent` field (a permission profile, generic tools, iteration and token limits) is admitted and clamped by App Hub. Since [#184](https://github.com/OctoSense-org/OctoSense/pull/184), an app that declares one, declares `octos.*`, or ships `tools.json` has an agent: once the person allows it, the shell prepares its peer `card.` with the bundle's tools (`crates/shell/src/agents.rs`), and the person can talk to it in the shell's "Ask " panel. The shell keeps the generic tools App Hub admits (`ask_user_question`), but does not apply the profile or the limits, or install `AGENT.md` or skills, yet. Rinx refuses to import a bundle that declares an agent. +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. ## Planned: event-driven app agents (ADR 0002) -[ADR 0002](adr/0002-event-driven-app-agents.md) (status **Proposed**) gives every app that asks for one **its own agent**: its app peer on the shell's one kernel, woken by the app's own triggers, working only through the app's own tools, publishing cards to the glance screen. Native modules and script apps follow one model (§12). The pieces and where each stands: +[ADR 0002](adr/0002-event-driven-app-agents.md) (status **Proposed**) describes the broader plan for event-driven app agents. App peers, tool execution and human conversations already work. Automatic triggers and other remaining pieces are listed separately below; the ADR’s proposed status does not mean every component is still planned. | Piece | ADR | Status | | --- | --- | --- | -| `tools.json`: tools named `.`, JSON Schema input and output, `risk` (`read`, `act`, `destructive`), `confirm` (`host` or `app`), `background`, `shareable`, `implemented_by` (`host-service` or `app`) | §4, §12 | App Hub admits and pins it ([App-Hub#18](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/18), `crates/app-policy/src/agent.rs`). No shell loads it yet. | -| `AGENT.md`, data-only skills, model **requirements** (never a provider or model name), `background`, `triggers` (cron, host-service events) | §2, §3 | Same: admitted by App Hub (`crates/app-policy/src/agent.rs`), and the shells' App Hub pin `e8601b80` includes them. No shell runs them yet. | +| `tools.json`: names, input/output schemas, risk, confirmation, sharing and implementation | §4, §12 | Loaded by `host_tools/script_apps.rs`, registered on peers and routed to host-service executors. News, Mail, Calendar, Photos, Maps, Camera and YouTube ship declarations; AI providers has no app agent. Arbitrary `implemented_by: "app"` script execution remains unavailable. | +| `AGENT.md`, data-only skills, model requirements, `background`, triggers | §2, §3 | Admitted metadata. Prompt/skill loading, model selection from these requirements and trigger scheduling remain unimplemented in the shell. Tool background eligibility alone does not schedule a turn. | | Kernel: host-registered tools per peer (`peer/tools/register`, `peer/tool/call`/`result`/`cancel`), tool-list and risk enforcement, approvals only on the host connection, an allowlist of generic tools, `peer/input` | §4, §13 | Kernel side merged: [octos#2567](https://github.com/octos-org/octos/pull/2567) (UPCR-2026-035), in the pin with its follow-ups (octos#2616). The shell side is on main: [#145](https://github.com/OctoSense-org/OctoSense/pull/145) (tool registration, the relay, `peer/input`) and G3 (per-app `generic_tools` from the manifests, `tools.json` loading, grants, executors for script apps' host services, schema and budget checks; `peer/input/reject`, octos#2621). | -| Risk decides supervision: read and in-app act run unattended; destructive waits for the person (`confirm: host`: the kernel's approval path; `confirm: app`: the app's own sheet when the person is present, an approval request in the app's conversation when absent) | §4, §12 | Declared in App Hub (#18) and octos#2567. The shell's approval router, sheets and standing rules are merged ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)) and take the AI services bus's `confirm: host` calls; since [#145](https://github.com/OctoSense-org/OctoSense/pull/145) the kernel's `host_tool` approvals reach it through the relay ([architecture § Approvals](architecture.md#5-approvals)). Rinx's `send_message` already works the `confirm: app` way on its own surface. | +| Tool approval policy | §4, §12 | Destructive and outward calls enter the shell’s approval router. It applies standing rules, host or registered app confirmation surfaces, and developer mode. Grants, schemas and caller budgets are checked separately. See [Approvals](architecture.md#5-approvals). | | News M1: the `news` data service (no model) | First slice | Merged ([#69](https://github.com/OctoSense-org/OctoSense/pull/69)); issue [#60](https://github.com/OctoSense-org/OctoSense/issues/60). | -| News M2: `os.news` gets a peer and its tools are registered | First slice | Planned: [#61](https://github.com/OctoSense-org/OctoSense/issues/61). | +| News M2: `os.news` gets a peer and tools | First slice | Implemented: manifest `agent`, `news.list`/`news.read`/`news.notify` tools, shell peer preparation and relay. | | News M3: triggers and an unattended run | First slice | Planned: [#62](https://github.com/OctoSense-org/OctoSense/issues/62). | -| News M4: glance cards (`glance.publish`, the glance page and desktop panel) | §7, §8 | `glance.publish` ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)) and the `glance` capability for contained apps ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), with [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) merged; in progress: `sys.digest` sources ([#87](https://github.com/OctoSense-org/OctoSense/pull/87), draft); issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63). | -| M5: the system toolbox (research, crawl) as granted tools | §6 | Planned: [#64](https://github.com/OctoSense-org/OctoSense/issues/64). Merged: the workflow templates ([#82](https://github.com/OctoSense-org/OctoSense/pull/82), `crates/toolbox`) and octos's research engine ([octos#2568](https://github.com/octos-org/octos/pull/2568)); in progress: offering the toolbox to app agents ([#108](https://github.com/OctoSense-org/OctoSense/pull/108), draft). | +| News M4: glance cards (`glance.publish`, the glance page and desktop panel) | §7, §8 | `glance.publish` ([#72](https://github.com/OctoSense-org/OctoSense/pull/72)) and the `glance` capability for contained apps ([#86](https://github.com/OctoSense-org/OctoSense/pull/86), with [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) merged; `sys.digest` integration has separate runtime/host requirements; [#87](https://github.com/OctoSense-org/OctoSense/pull/87) is historical tracking; issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63). | +| M5: the system toolbox as granted tools | §6 | Implemented behind `toolbox-peers`: `crates/ai-host/src/toolbox_peers.rs` and the shell toolbox executor. Home enables the feature by default; desktop opts in. Tools still require admission/grants and consent; this is not a general conversation with the system agent. | | M6: render and critique (`card-studio`) | §7 | App Hub's `card-studio` crate merged ([App-Hub#19](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/19)); the skill is planned ([#65](https://github.com/OctoSense-org/OctoSense/issues/65)). | -| M7: the per-app conversation (approvals, questions), memory | §9, §10 | Planned: [#66](https://github.com/OctoSense-org/OctoSense/issues/66). The shell-side approval sheets and consent exist ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)). | +| M7: app conversations, questions and memory | §9, §10 | Implemented human/system lanes, Ask-app panel, `sys.chat`, host-routed questions/approvals and scoped peer/context memory. See the [architecture](architecture.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. @@ -219,18 +241,18 @@ The tracking issue is [#68](https://github.com/OctoSense-org/OctoSense/issues/68 ### Desktop, with a throwaway kernel and profile -1. Build octos at the revision the root `Cargo.toml` pins (`ae230ce0`), in a checkout of [octos-org/octos](https://github.com/octos-org/octos) (the flags are `tools/kernel-artifact.py`'s; **unverified** at this revision in this page's refresh): +1. Build 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. ```sh - git checkout ae230ce04d57f3c29cf6c2518e5956a86c07d788 - cargo build --release -p octos-cli --bin octos --no-default-features --features api,git,ast + python3 tools/kernel-artifact.py --host --plan + python3 tools/kernel-artifact.py --host ``` 2. Run the desktop with its own state, core dir and file vaults, so neither `~/.octosense`, `~/octos-home` nor the login keychain is touched: ```sh T=$(mktemp -d) - OCTOS_APP_CORE_BIN=/path/to/octos/target/release/octos \ + OCTOS_APP_CORE_BIN="$PWD/target/octos-kernel/target/release/octos" \ OCTOS_APP_CORE_DIR=$T/octos-home/.octos \ OCTOSENSE_HOME=$T/state OCTOSENSE_APP_DATA=$T/apps \ OCTOSENSE_LLM_VAULT=file OCTOSENSE_MAIL_VAULT=file \ diff --git a/docs/ai-services.zh-CN.md b/docs/ai-services.zh-CN.md index 932c452f..7e8fbe5e 100644 --- a/docs/ai-services.zh-CN.md +++ b/docs/ai-services.zh-CN.md @@ -25,16 +25,16 @@ | 每个 Shell 进程一个 octos 内核,首次使用时启动,提供方变更后重启 | 目前可用(设置了 `OCTOS_APP_CORE_BIN` 的桌面端、Android、OpenHarmony;iOS 没有) | [`crates/kernel`](../crates/kernel/README.md) | | AI providers:用户的模型提供方和密钥,密钥只在宿主面板上输入 | 目前可用 | [`apps/ai-providers`](../apps/ai-providers/host-service/README.md) | | Shell 的 AI 入口(`start`、策略、按实例提供服务、QR 导入) | 目前可用 | [`crates/ai-host`](../crates/ai-host/README.md) | -| 宿主拥有的应用 peer:每个获授权的应用一个 octos peer,归系统 Agent 所有 | 目前可用:原生模块(Rinx),以及在开关打开时的隔离脚本应用 | [`crates/app-peers`](../crates/app-peers/README.md)、[Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | +| 宿主拥有的应用 peer:每个获授权的应用/账号一个 octos peer,归系统 Agent 所有 | 已实现:原生模块(Rinx)及经过按应用同意的隔离脚本应用 | [`crates/app-peers`](../crates/app-peers/README.md)、[Rinx ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md) | | 在 Shell 内核上运行的 AppCard("Ask anything") | 目前可用,需主动开启(`--features app-appcard`),不随产品发布 | [`apps/appcard`](../apps/appcard) | -| 隔离运行的脚本应用(系统应用或商店应用)向助手提问 | 在托管了内核的 Shell 中可用([#106](https://github.com/OctoSense-org/OctoSense/pull/106)):`octos` 宿主服务为每个应用分配自己的 peer(`card.<应用 id>`),前提是用户在首次使用时允许了该应用的 Agent([#120](https://github.com/OctoSense-org/OctoSense/pull/120),默认行为;`OCTOSENSE_CONTAINED_APPS=1` 不询问任何人,`0` 关闭该服务)。peer 发起的工具审批交给 Shell 的审批路由和它的面板处理。`llm` 仍是只供 `os.*` 应用使用的提供方管理服务 | [见下文](#隔离运行的脚本应用系统应用和商店应用) | +| 隔离运行的脚本应用(系统应用或商店应用)向助手提问 | 在托管内核的 Shell 中可用([#106](https://github.com/OctoSense-org/OctoSense/pull/106)):用户首次同意后,每个应用获得自己的 peer。工具审批使用 Shell 的审批面板。`llm` 仍是只供 `os.*` 应用使用的提供方管理服务 | [同意设置](#隔离应用的首次使用同意);[下文的调用与回复](#隔离运行的脚本应用系统应用和商店应用) | | 供隔离应用使用的一次性模型调用(`model`,`model.complete`) | 目前可用([#95](https://github.com/OctoSense-org/OctoSense/pull/95)):由 `crates/ai-host` 与 `llm` 服务一同注册,供获得 `model` 权限的应用使用([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24),已在 Shell 锁定的 App Hub 中) | [见下文](#隔离运行的脚本应用系统应用和商店应用) | | News 数据服务(`news`,不使用模型) | 已合入([#69](https://github.com/OctoSense-org/OctoSense/pull/69));只响应 `os.*` 应用 | [`apps/news/host-service`](../apps/news/host-service/README.md) | -| `glance.publish`:glance 屏幕上的 L0 卡片 | 已合入([#72](https://github.com/OctoSense-org/OctoSense/pull/72));获得 `glance` 权限的隔离应用可以发布([#86](https://github.com/OctoSense-org/OctoSense/pull/86))。进行中:`sys.digest` 数据源([#87](https://github.com/OctoSense-org/OctoSense/pull/87),草稿) | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | -| 审批、首次使用同意、开发者模式 | 目前可用([#120](https://github.com/OctoSense-org/OctoSense/pull/120)、[#118](https://github.com/OctoSense-org/OctoSense/pull/118)):Shell 的审批路由、常设规则和审批面板,目前只接收 AI 服务总线的调用;应用的 Agent 首次运行前征求同意;开发者模式只能由用户打开 | [架构 § 审批](architecture.zh-CN.md#5-审批) | +| `glance.publish`:L0/L1 source 卡片或 Splash script 卡片 | 已合入([#72](https://github.com/OctoSense-org/OctoSense/pull/72));获得 `glance` 权限的隔离应用可以发布([#86](https://github.com/OctoSense-org/OctoSense/pull/86))。`sys.digest` 有单独的运行时/宿主要求;[#87](https://github.com/OctoSense-org/OctoSense/pull/87) 是历史跟踪链接,不表示当前 PR 状态 | [`crates/shell/src/glance.rs`](../crates/shell/src/glance.rs) | +| 审批、首次使用同意、开发者模式 | 已实现:Shell 审批路由、常设规则及面板接收 AI 服务总线和内核工具审批;首次运行先征求同意,开发者模式由用户开启 | [架构 § 审批](architecture.zh-CN.md#5-审批) | | 系统 Agent 的工具集 | 目前可用,已强制:从不提供 octos 的 shell(`_main` profile 的 `tool_policy`,[#117](https://github.com/OctoSense-org/OctoSense/pull/117)),且每次内核启动都设置系统会话的精确内核工具列表(`session/tool_list/set`,octos#2648) | [架构 § 工具与授权](architecture.zh-CN.md#4-工具与授权) | | 原生应用只声明一次(`native-apps.json`),按目标平台决定托管方式;Terminal 作为系统应用在桌面端以独立进程运行 | 目前可用([#113](https://github.com/OctoSense-org/OctoSense/pull/113)) | [架构 § 原生应用](architecture.zh-CN.md#原生应用进程内还是独立进程) | -| 应用自己的 Agent:`tools.json`、`AGENT.md`、skills、模型需求、触发器 | 规划中([ADR 0002](adr/0002-event-driven-app-agents.md),Proposed)。App Hub 接受这些文件([App-Hub#18](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/18));没有 Shell 运行它们;内核一侧进行中([octos#2567](https://github.com/octos-org/octos/pull/2567),草稿) | [见下文](#规划中事件驱动的应用-agentadr-0002) | +| 应用自己的 Agent:声明与执行 | News/Mail/Calendar/Photos/Maps/Camera/YouTube 的 `tools.json`、通用工具授权、peer 和宿主服务执行器已实现。`AGENT.md` 提示词加载、包内 skills/模型选择和自动触发器仍有缺口 | [见下文](#规划中事件驱动的应用-agentadr-0002) | | 独立进程中的原生应用访问自己的 Agent(peer link,ADR 0004 §5) | 规划中(计划第 8 步)。Makepad 的客户端一侧已合入([OctoSense-org/makepad#54](https://github.com/OctoSense-org/makepad/pull/54),`makepad_ai_services::peer`);Shell 一侧尚未实现(`crates/shell/src/hub.rs` 中没有) | [架构 § 应用与它自己的 Agent](architecture.zh-CN.md#应用与它自己的-agent) | ## 架构 @@ -105,7 +105,21 @@ flowchart TB [`crates/ai-host`](../crates/ai-host/README.md)(`octosense-ai-host`)是两个 Shell 都调用的入口:启动时调用 `start(Host::platform(data_dir))`(配置内核、安装宿主策略、注册带平台 QR 导入能力的 `llm`),每个事件调用 `handle_event`,在原生模块 `create` 前后调用 `offer(module, scope)` / `finish()`,退出时调用 `shutdown()`。 -宿主**策略**按精确的 `octos.*` 服务名决定哪些原生模块可以使用助手,以及隔离应用是否能使用 `octos` 服务。`Policy::shipped()` 只把这四个服务授予 `rinx`,并让隔离应用经过首次使用同意(`ContainedGate::Consent`,`crates/ai-host/src/lib.rs` 中的 `contained_gate_from`):`OCTOSENSE_CONTAINED_APPS=1` 是不询问任何人的开发者覆盖开关,`0` 为所有应用关闭 `octos` 服务。用户按应用的开关是**首次使用同意**([#120](https://github.com/OctoSense-org/OctoSense/pull/120),`crates/shell/src/approvals/consent.rs`):应用第一次请求它的 Agent 时,Shell 显示它可以读取和使用什么、模型在哪里运行;**设置 → 助手 → 审批**列出每个应用的 Agent,并带有关闭开关([架构 § 审批](architecture.zh-CN.md#5-审批))。 +宿主**策略**按精确的 `octos.*` 服务名决定哪些原生模块可以使用助手,以及隔离应用是否能使用 `octos` 服务。在原生模块中,`Policy::shipped()` 只把这四个服务授予 `rinx`。 + +#### 隔离应用的首次使用同意 + +隔离应用默认需要用户在首次使用时同意。环境变量 `OCTOSENSE_CONTAINED_APPS` 控制这项策略: + +| 设置 | 行为 | +| --- | --- | +| 未设置(默认) | 应用首次使用自己的 Agent 前,先询问用户(`ContainedGate::Consent`)。 | +| `1` | 开发者覆盖设置:跳过首次使用同意。每次工具调用的审批仍按各自规则处理。 | +| `0` | 为隔离应用关闭 `octos` 服务。 | + +首次使用时,Shell 会说明应用的 Agent 可以读取和使用什么,以及模型在哪里运行。**设置 → 助手 → 审批**列出每个应用的 Agent,用户可以在此关闭它。 + +策略由 [`crates/ai-host/src/lib.rs`](../crates/ai-host/src/lib.rs) 中的 `contained_gate_from` 选择。每个应用的同意状态由 [`crates/shell/src/approvals/consent.rs`](../crates/shell/src/approvals/consent.rs) 处理([#120](https://github.com/OctoSense-org/OctoSense/pull/120));详见[架构 § 审批](architecture.zh-CN.md#5-审批)。 ### `crates/app-peers`:宿主拥有的应用 peer @@ -174,7 +188,13 @@ flowchart TB | `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")` 时从中读取 | | `glance` | 获得 `glance` 权限的应用([#86](https://github.com/OctoSense-org/OctoSense/pull/86)、[App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22)) | 以应用自己的 id 向 glance 屏幕发布 L0 卡片(`crates/shell/src/glance.rs`) | | `model` | 获得 `model` 权限的应用([App-Hub#24](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/24)) | 一次性的 `model.complete {task, input, schema, class?, allow_urls?}` 和 `model.budget`([#95](https://github.com/OctoSense-org/OctoSense/pull/95),`apps/ai-providers/host-service/src/complete/`,在 `crates/ai-host/src/lib.rs` 中注册):`class` 为 `fast` 或 `strong`;宿主从用户的提供方中挑选模型,按 schema 校验回复,除非请求否则拒绝含 URL 的回复,按应用管理每日预算;没有工具、记忆和历史,应用也看不到任何密钥 | -| `octos` | manifest 声明了确切 `octos.*` 名称的任何应用;前提是 Shell 托管了内核,且用户在首次使用时允许了该应用的 Agent(`consent_for_contained`,[#120](https://github.com/OctoSense-org/OctoSense/pull/120);`OCTOSENSE_CONTAINED_APPS=1` 不询问任何人,`0` 关闭它) | 助手:经应用自己的、由宿主拥有的 peer `card.<应用 id>`(`crates/ai-host/src/contained.rs`,[#106](https://github.com/OctoSense-org/OctoSense/pull/106))。四个 `octos.*` 调用(`octos.turn.start` 接受 `text`,非空白、最多 32 KiB,并可选 `trigger`,取 `person`、`app` 或 `incoming` 之一,以及 `from`;其余只接受 `{}`)。peer 发起的工具审批交给 Shell 的审批路由和它的面板(ADR 0004 §8);只有没有审批路由的宿主才会拒绝它们,并列在回复的 `denied_approvals` 中。开发者模式下由它为覆盖的应用作答(`crates/app-peers/src/host_approvals.rs`)。超过 2 MiB 的回复会被拒绝 | +| `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.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)。 +- **回复。** 宿主拒绝超过 2 MiB 的回复。下表列出成功调用及常见错误的返回内容。 因此,隔离运行的应用(商店应用或系统应用)只能通过 `octos.*` 使用助手,且需要 Shell 托管了内核。它会收到: @@ -192,25 +212,27 @@ flowchart TB 第一行、`llm` 一行和 `card-host` 一行已于 2026-09-27 在 `card-host`(App Hub `362d832`)中运行验证。回复、参数不合规的返回和缺少内核的返回已于 2026-09-28 在 macOS 上运行验证:release 版桌面端、隐藏窗口,经启动器打开一个声明了 `octos.session.open` 和 `octos.turn.start` 的系统应用;使用按当时锁定的 octos `7bec0918` 构建的内核和用户自己的提供方时,回复来自 peer `card.<应用 id>`,内核数据中出现了它的记忆命名空间 `app/card.<应用 id>/…`。文本长度和开关关闭的返回由 `cargo test -p octosense-ai-host` 覆盖,走的是同一个分发函数。OctoScript-App-Design-Flow 的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 给出了示例应用,以及 Rinx 提供的四个 `octos.*` 调用的参数和返回形状。 -manifest 的 `agent` 字段(权限档位、通用工具、迭代和 token 上限)会被 App Hub 接受并按上限裁剪。自 [#184](https://github.com/OctoSense-org/OctoSense/pull/184) 起,声明了它、声明了 `octos.*` 或附带 `tools.json` 的应用都有 Agent:用户允许后,Shell 用应用包中的工具为它准备 peer `card.<应用 id>`(`crates/shell/src/agents.rs`),用户可以在 Shell 的“Ask ”面板中与它对话。Shell 保留 App Hub 接受的通用工具(`ask_user_question`),但还不应用权限档位和上限,也不安装 `AGENT.md` 或技能。Rinx 会拒绝导入声明了 Agent 的应用包。 +声明了 `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 的应用包。 ## 规划中:事件驱动的应用 Agent(ADR 0002) -[ADR 0002](adr/0002-event-driven-app-agents.md)(状态 **Proposed**)让每个申请的应用拥有**自己的 Agent**:在 Shell 唯一内核上的应用 peer,由应用自己的触发器唤醒,只通过应用自己的工具工作,把卡片发布到 glance 屏幕。原生模块和脚本应用遵循同一模型(§12)。各部分及其进展: +[ADR 0002](adr/0002-event-driven-app-agents.md)(状态 **Proposed**)描述事件驱动应用 Agent 的完整计划。应用 peer、工具执行和用户对话已经可用。自动触发器等剩余部分在下表单独列出;ADR 仍处于提案状态,并不表示所有组件都尚未实现。 | 组成部分 | ADR | 状态 | | --- | --- | --- | -| `tools.json`:名为 `.` 的工具,JSON Schema 输入输出,`risk`(`read`、`act`、`destructive`),`confirm`(`host` 或 `app`),`background`、`shareable`、`implemented_by`(`host-service` 或 `app`) | §4、§12 | App Hub 接受并锁定([App-Hub#18](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/18),`crates/app-policy/src/agent.rs`)。目前没有 Shell 加载它。 | -| `AGENT.md`、只含数据的 skills、模型**需求**(从不写提供方或模型名)、`background`、`triggers`(cron、宿主服务事件) | §2、§3 | 同上:App Hub 已接受(`crates/app-policy/src/agent.rs`),Shell 锁定的 App Hub `e8601b80` 已包含这些字段。目前还没有 Shell 运行它们。 | -| 内核:按 peer 由宿主注册工具(`peer/tools/register`、`peer/tool/call`/`result`/`cancel`),强制工具列表和风险等级,审批只在宿主连接上进行,通用工具白名单,`peer/input` | §4、§13 | 进行中:[octos#2567](https://github.com/octos-org/octos/pull/2567)(UPCR-2026-035,草稿)。Shell 一侧是 ADR 0004 计划第 6 步。 | -| 风险决定监督方式:read 和应用内 act 无人值守运行;destructive 等待用户(`confirm: host`:内核的审批路径;`confirm: app`:用户在场时用应用自己的面板,不在场时在应用的对话中生成审批请求) | §4、§12 | 已在 App Hub(#18)和 octos#2567 中声明。Shell 的审批路由、审批面板和常设规则已合入([#120](https://github.com/OctoSense-org/OctoSense/pull/120)),接收 AI 服务总线的 `confirm: host` 调用;内核工具调用要等 octos#2567 合入后才会进入([架构 § 审批](architecture.zh-CN.md#5-审批))。Rinx 的 `send_message` 已经在自己的界面上按 `confirm: app` 的方式工作。 | +| `tools.json`:名称、输入输出 schema、风险、确认、共享和实现 | §4、§12 | `host_tools/script_apps.rs` 已加载、注册到 peer 并转发到宿主服务执行器;News/Mail/Calendar/Photos/Maps/Camera/YouTube 已声明工具。任意 `implemented_by: "app"` 脚本工具执行仍不可用。 | +| `AGENT.md`、只含数据的 skills、模型需求、`background` 和触发器 | §2、§3 | 已准入的元数据;Shell 尚未实现提示词/skill 加载、按这些需求选模型和触发调度。工具可后台运行不等于会自动启动回合。 | +| 内核:宿主注册工具、风险/列表检查、宿主审批、通用工具白名单和 `peer/input` | §4、§13 | 已实现并在锁定版本中;Shell 注册工具、接收输入、检查 schema/预算并通过 relay 调用执行器。见 `crates/app-peers` 和 `crates/shell/src/host_tools/`。 | +| 工具审批策略 | §4、§12 | 破坏性和对外调用进入 Shell 的审批路由,由它应用常设规则、宿主或已注册的应用确认界面,以及开发者模式。授权、schema 和调用方预算另行检查。详见[审批](architecture.zh-CN.md#5-审批)。 | | News M1:`news` 数据服务(不使用模型) | 第一个切片 | 已合入([#69](https://github.com/OctoSense-org/OctoSense/pull/69));issue [#60](https://github.com/OctoSense-org/OctoSense/issues/60)。 | -| News M2:`os.news` 获得 peer,并注册它的工具 | 第一个切片 | 规划中:[#61](https://github.com/OctoSense-org/OctoSense/issues/61)。 | +| News M2:`os.news` peer 及工具 | 第一个切片 | 已实现:manifest `agent`、`news.list`/`news.read`/`news.notify`、Shell peer 准备与 relay。 | | News M3:触发器和无人值守运行 | 第一个切片 | 规划中:[#62](https://github.com/OctoSense-org/OctoSense/issues/62)。 | -| News M4:glance 卡片(`glance.publish`、glance 页面和桌面面板) | §7、§8 | `glance.publish`([#72](https://github.com/OctoSense-org/OctoSense/pull/72))和供隔离应用使用的 `glance` 权限([#86](https://github.com/OctoSense-org/OctoSense/pull/86),配合 [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22))已合入;进行中:`sys.digest` 数据源([#87](https://github.com/OctoSense-org/OctoSense/pull/87),草稿);issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63)。 | -| M5:系统工具箱(检索、抓取)作为可授予的工具 | §6 | 规划中:[#64](https://github.com/OctoSense-org/OctoSense/issues/64)。已合入:工作流模板([#82](https://github.com/OctoSense-org/OctoSense/pull/82),`crates/toolbox`)和 octos 的检索引擎([octos#2568](https://github.com/octos-org/octos/pull/2568));进行中:把工具箱提供给应用 Agent([#108](https://github.com/OctoSense-org/OctoSense/pull/108),草稿)。 | +| News M4:glance 卡片(`glance.publish`、glance 页面和桌面面板) | §7、§8 | `glance.publish`([#72](https://github.com/OctoSense-org/OctoSense/pull/72))和供隔离应用使用的 `glance` 权限([#86](https://github.com/OctoSense-org/OctoSense/pull/86),配合 [App-Hub#22](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/22))已合入;`sys.digest` 有单独的运行时/宿主要求;[#87](https://github.com/OctoSense-org/OctoSense/pull/87) 是历史跟踪链接,不表示当前 PR 状态;issue [#63](https://github.com/OctoSense-org/OctoSense/issues/63)。 | +| M5:作为获授权工具的系统工具箱 | §6 | 已在 `toolbox-peers` feature 下实现,见 `crates/ai-host/src/toolbox_peers.rs` 和 Shell 工具箱执行器。Home 默认开启,桌面需显式开启;仍需准入、授权和同意,不是与系统 Agent 的通用对话。 | | M6:渲染与评审(`card-studio`) | §7 | App Hub 的 `card-studio` crate 已合入([App-Hub#19](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/19));对应 skill 规划中([#65](https://github.com/OctoSense-org/OctoSense/issues/65))。 | -| M7:每个应用的对话(审批、提问)、记忆 | §9、§10 | 规划中:[#66](https://github.com/OctoSense-org/OctoSense/issues/66)。Shell 一侧的审批面板和同意已存在([#120](https://github.com/OctoSense-org/OctoSense/pull/120))。 | +| M7:应用对话、问题和记忆 | §9、§10 | 已实现人类/系统通道、Ask-app 面板、`sys.chat`、宿主路由的问题/审批及 peer/context 记忆。见[导读](architecture.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)。 @@ -219,18 +241,18 @@ manifest 的 `agent` 字段(权限档位、通用工具、迭代和 token 上 ### 桌面端:使用临时的内核与配置 -1. 在 [octos-org/octos](https://github.com/octos-org/octos) 的检出中,构建根 `Cargo.toml` 锁定的版本(`ae230ce0`;参数与 `tools/kernel-artifact.py` 相同;本次更新未在此版本上运行,**unverified**): +1. 在 OctoSense 仓库根目录构建桌面内核。现有脚本读取 `Cargo.lock` 锁定的 octos 版本,并使用独立目录 `target/octos-kernel/`,不会切换其他检出的分支。构建和后续启动步骤均**未验证(unverified)**;本次只检查了 `--plan` 输出。 ```sh - git checkout ae230ce04d57f3c29cf6c2518e5956a86c07d788 - cargo build --release -p octos-cli --bin octos --no-default-features --features api,git,ast + python3 tools/kernel-artifact.py --host --plan + python3 tools/kernel-artifact.py --host ``` 2. 用独立的状态目录、core 目录和文件密钥库运行桌面端,这样不会动到 `~/.octosense`、`~/octos-home` 和登录钥匙串: ```sh T=$(mktemp -d) - OCTOS_APP_CORE_BIN=/path/to/octos/target/release/octos \ + OCTOS_APP_CORE_BIN="$PWD/target/octos-kernel/target/release/octos" \ OCTOS_APP_CORE_DIR=$T/octos-home/.octos \ OCTOSENSE_HOME=$T/state OCTOSENSE_APP_DATA=$T/apps \ OCTOSENSE_LLM_VAULT=file OCTOSENSE_MAIL_VAULT=file \ From 8f9954ed4092c2927ff98f1be8dacc120c0b08ce Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:44:44 -0700 Subject: [PATCH 3/3] docs: align final review corrections and companion links --- docs/ai-services.md | 44 ++++++++++++++++++++++--------------- docs/ai-services.zh-CN.md | 46 ++++++++++++++++++++++----------------- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/docs/ai-services.md b/docs/ai-services.md index 949f43ad..4a3ba81b 100644 --- a/docs/ai-services.md +++ b/docs/ai-services.md @@ -2,7 +2,9 @@ English | [简体中文](ai-services.zh-CN.md) -How the assistant is wired into OctoSense: the [octos](https://github.com/octos-org/octos) agent kernel the shell runs, where the person configures it, which apps may use it and how, and what is planned. It describes `main` as of 2026-09-28 (OctoSense `ad0d738`, which pins octos `5e7577f0` and OctoSense-App-Hub `e8601b80`); on 2026-09-29 the statements about octos#2567, host tools and approvals, the peer link, the system chat and command execution were rechecked against OctoSense `baa90bd`, which pins octos `acffad3b` and the same App Hub. Everything under **Works today** was read in that code; **In progress** means an open pull request; **Planned** means an ADR or an open issue, with nothing merged yet. +How the assistant is wired into OctoSense: the octos kernel, provider configuration, app peers and tools. 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. + +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. This page is about the assistant *inside* OctoSense. Building an app needs no AI service and no particular coding agent: the app harness, [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow), works with any agent or none. Its [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) page is the app developer's short version of this one. @@ -47,7 +49,7 @@ flowchart TB sheet["Host sheets
key, QR, PIN"] llm["llm host service
writes the provider profile"] aihost["crates/ai-host
start, policy, offer"] - broker["crates/app-peers broker
one peer per granted native app"] + broker["crates/app-peers broker
one peer per granted app/account"] runner["Card runner (App Hub)
host services: mail, news, glance, llm, model, octos"] router["Approval router
crates/shell/src/approvals"] bus["AI services bus
crates/shell/src/ai_bus.rs"] @@ -69,7 +71,7 @@ flowchart TB rinx -- "scoped OctosAppService" --> broker appcard -- "its own connection" --> kernel scripts -- "host.request" --> runner - runner -- "octos.* service
peer card.<app id>" --> broker + runner -- "octos.* service
broker identity card.<app id>" --> broker rinx -- "typed tools" --> bus bus -- "confirm: host calls" --> router router --> person @@ -77,18 +79,18 @@ flowchart TB ### The octos kernel: one per shell -The kernel is a **shell service** ([`crates/kernel`](../crates/kernel/README.md), package `octosense-kernel`), not an app. The shell configures it once at startup; nothing runs until the first consumer calls `octosense_kernel::connect()`, and later consumers share the same process. octos holds a single-writer lock on its data dir, so there is one kernel per core dir. When the last connection closes the kernel stops; `shutdown()` stops it with the shell (5 s at most). +The kernel is a **shell service** ([`crates/kernel`](../crates/kernel/README.md), package `octosense-kernel`), not an app. The shell configures it once at startup; nothing runs until the first consumer calls `octosense_kernel::connect()`, and later consumers share the same process. octos holds a single-writer lock on its data dir, so there is one kernel per core dir. In ordinary mode, when the last connection closes the kernel stops; Talk to Octos keeps the shared kernel alive while enabled; `shutdown()` stops it with the shell (5 s at most). How it runs, by platform (`crates/kernel/src/launch.rs`, `KernelSource::platform()` in `crates/ai-host`): | Platform | Kernel | Core dir (the octos home) | | --- | --- | --- | -| Desktop (macOS; Windows and Linux untested) | `$OCTOS_APP_CORE_BIN serve --stdio --data-dir ` (plus `--config /config.json` if present). **Without `OCTOS_APP_CORE_BIN` there is no kernel**, and a developer's own `octos serve` is never touched. Packaging the kernel next to the desktop binary is in progress ([#85](https://github.com/OctoSense-org/OctoSense/pull/85)). | `$OCTOS_APP_CORE_DIR`, else `/octos-home/.octos` (`~/.octosense/octos-home/.octos`): OctoSense's own, no longer the person's `~/octos-home/.octos`, whose provider settings it copies once | +| Desktop (macOS; Windows and Linux untested) | `$OCTOS_APP_CORE_BIN serve --stdio --data-dir ` (plus `--config /config.json` if present). **Without an explicit kernel program or `OCTOS_APP_CORE_BIN` there is no desktop kernel**, and a developer's own `octos serve` is never touched. Kernel packaging was tracked in [#85](https://github.com/OctoSense-org/OctoSense/pull/85); this recipe uses an explicit binary. | `$OCTOS_APP_CORE_DIR`, else `/octos-home/.octos` (`~/.octosense/octos-home/.octos`): OctoSense's own, no longer the person's `~/octos-home/.octos`, whose provider settings it copies once | | Android (Home) | The APK's `liboctos.so serve --stdio`, built by [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) from the octos revision the root `Cargo.toml` pins | `/octos-home/.octos` | | OpenHarmony | In process (`octos_cli::embedded::serve_io`), because a HAP may not exec | `/octos-home/.octos` | | iOS | **None.** Providers are still saved; no app gets an assistant | – | -Consumers speak the octos UI Protocol (JSON-RPC frames, as `octos serve --stdio` does) over a `Connection`. Each consumer gets the replies to its own requests and the notifications of its own sessions. When the providers change, the kernel restarts and every connection ends with `CloseReason::Restarted`; a consumer reconnects and reopens its sessions (AppCard's transport is the reference). +With Talk to Octos enabled, the kernel uses host-managed loopback WebSocket transport instead of stdio. Consumers speak the octos UI Protocol (JSON-RPC frames, as `octos serve --stdio` does) over a `Connection`. Each consumer gets the replies to its own requests and the notifications of its own sessions. When the providers change, the kernel restarts and every connection ends with `CloseReason::Restarted`; a consumer reconnects and reopens its sessions (AppCard's transport is the reference). ### AI providers and the `llm` host service @@ -125,15 +127,19 @@ The policy is selected by `contained_gate_from` in [`crates/ai-host/src/lib.rs`] [`crates/app-peers`](../crates/app-peers/README.md) is the broker between an app and the kernel (Rinx [ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md); kernel side octos UPCR-2026-034): -- A native module whose declared `octos.*` services the policy grants gets **one octos peer** for the app, created or resumed with `peer/prepare` on the shell's kernel. A module with nothing granted allocates no peer. +- A native module whose declared `octos.*` services the policy grants gets **one octos peer per account**, created or resumed with `peer/prepare` on the shell's kernel. A module with nothing granted allocates no peer. - The peer's **owner** is the shell's system agent session, `_main:api:octosense#system`. The kernel mints a host token for the peer; the shell keeps it in `/../app-peers` (0600), outside every app's reach. -- The peer's **memory namespace** is `app//acct-`: per app and per app account (the hash is a non-secret tag of the account id). The kernel provisions its workspace. A kernel without this contract is refused, never replaced by an ordinary session on the profile's memory. -- The app never sees the kernel protocol. It gets a scoped `OctosAppService` for the instance being created, binds its signed-in account, and opens one **request context** per client instance (`peer/context/open`). A change of account revokes every context of the old account; late events are dropped. -- The operations are `Open`, `History`, `Turn { text }`, `Interrupt` and `Approval { id, approve }`, each gated by its exact service (`octos.session.open`, `octos.session.history`, `octos.turn.start`, `octos.turn.interrupt`; an approval needs `octos.turn.start`). Turns time out after 180 s. +- The peer's **memory namespace** is `app//acct-`: per app and per app account (the hash is a non-secret tag of the account id). The shell selects the permitted account workspace; the kernel provisions and verifies it. A kernel without this contract is refused, never replaced by an ordinary session on the profile's memory. +- The app never sees the kernel protocol. It gets a scoped `OctosAppService` for the instance being created, binds its signed-in account, and opens one **request context** per client instance (`peer/context/open`). A request context is a distinct kernel session under the same peer, not another app peer. `open_conversation` creates the human lane with bounded shared history; the peer session handles system-delegated work. A change of account revokes every context of the old account; late events are dropped. +- The operations are `Open`, `History`, `Turn { text }`, `Interrupt` and `Approval { id, approve }`, each gated by its exact service (`octos.session.open`, `octos.session.history`, `octos.turn.start`, `octos.turn.interrupt`; an approval needs `octos.turn.start`). The broker default turn timeout is 180 s. ### The system agent -Today the system agent is the **owner** of every app peer: the session that created it and can address it. It does not hold any app's tools, and it cannot answer an app peer's approvals (octos [#2560](https://github.com/octos-org/octos/pull/2560)). Its tools are a defined set the shell writes before every kernel start, with octos's shell never offered ([#117](https://github.com/OctoSense-org/OctoSense/pull/117), `crates/kernel/src/system_tools.rs`; see [architecture § Tools and grants](architecture.md#4-tools-and-grants)). The person reaches it in the shell's **system chat** ([#132](https://github.com/OctoSense-org/OctoSense/pull/132), `crates/shell/src/system_chat/`: Setup → Assistant → Assistant chat, F8, the desktop dock's Assistant icon, or the phone home's Assistant tile; full screen on a phone), whose approvals go through the approval router, or from a Talk to Octos client ([#98](https://github.com/OctoSense-org/OctoSense/pull/98), [ADR 0003](adr/0003-shared-octos-client-access.md)). Its larger role in ADR 0002 (supervising app agents, budgets, the kill switch, ranking the glance screen, improving app agents) is **planned**; the glance screen currently orders cards by priority and recency. +The system agent owns the app peers and uses `peer_send_input` to delegate, then `peer_gather` to obtain results. `agents.list` discovers available app agents; `agents.ask` requests first-use consent/preparation, not the delegated task itself. + +The person reaches the system chat through F8 or the shell's Assistant entry (`crates/shell/src/system_chat/`), and can talk directly to an app through the desktop “Ask <app>” panel or a card's `sys.chat`. Phone touch navigation has no Ask-app panel entry yet. + +The system agent has a restricted kernel roster (`system_tools.rs`) and selected shell tools such as opt-in `terminal.run`; it does not inherit every app tool and cannot approve for the person. Talk to Octos is a separate client-access option. Automatic trigger orchestration, learning overlays and richer glance ranking remain planned; cards currently sort by priority and recency. ### Other assistants in the shell @@ -146,8 +152,8 @@ Today the system agent is the **owner** of every app peer: the session that crea | --- | --- | | **Keys stay with the host.** | Only the `llm` service reads or writes keys; they live in the platform vault or the owner-only profile under the kernel's core dir, never in an app's jail. The app-peers contract carries no credentials (`ModelInfo` has none). No `octos.*` service lets an app choose a provider or submit a key. | | **Secrets are the host's.** | No app collects a password, PIN, key or one-time code, not even to pass it on. The runtime makes a password field inert in a policed isolate, App Hub's gate refuses a bundle that declares one, and services ask on their own sheets (`.sheet.*` is accepted only from the sheet). | -| **Approvals belong to the person, in the owning app.** | A tool approval raised in an app's context is answered only by `ContextOp::Approval` from that app's own UI; the system agent never approves for an app (app-peers policy, octos #2560). Rinx's `send_message` shows the room and the exact text in Rinx's own sheet and sends only on the person's yes. The shell's approval router ([#120](https://github.com/OctoSense-org/OctoSense/pull/120)) answers only on the person's gesture, live on a shell-drawn sheet or by a standing rule the person made; standing rules on "people in my contacts" use the person's contacts only after they turn on "Use my contacts in approval rules" ([architecture § Approvals](architecture.md#5-approvals)). Developer mode answers every approval for the apps it covers, and only the person turns it on ([#118](https://github.com/OctoSense-org/OctoSense/pull/118)). | -| **The system agent drives an app through its app agent.** | It owns the peers but holds no app tools; an app's tools run in the app (Rinx: `src/assistant`, "the system agent never holds these tools itself, it asks Rinx's peer"). | +| **Approvals belong to the person.** | The shell routes both `host_tool` and other kernel-tool approvals through its host-owned router; the app receives `approval/handled_by_host`. `confirm: app` uses an explicitly registered owning-app sheet. A system agent cannot approve for the person. Standing rules and developer mode are user-controlled; tool-specific restrictions still apply, including Terminal's non-auto-approvable command confirmation. See [Approvals](architecture.md#5-approvals). | +| **Delegation and tool execution have separate authority.** | The system agent delegates to app peers; the relay executes declared tools as their owner after grant/schema/policy checks. Cross-app direct tool grants are explicit, not access to all app APIs or databases. The system session separately has reviewed shell tools such as `terminal.run`. | | **Memory is private per app and account.** | Each peer's memory namespace is `app//acct-`; contexts of one account are never restored under another. Promotion to shared memory is planned (ADR 0002 §9). | | **Least privilege, by exact name.** | An app gets `declared ∩ supported ∩ host policy` services, compared by exact name: `octos.` or `octos.admin` grants nothing. | @@ -173,7 +179,9 @@ A native module is trusted Rust linked into the shell. **Rinx** ([hagency-org/Ri 4. `availability()` reports `Unavailable` (no kernel, not granted, signed out), `Idle`, `Ready` or `Failed`; the app's ordinary UI keeps working in every state. `settings_entry()` is `Host`: the app offers no provider form of its own and points the person to AI providers. -**Tools.** Rinx defines its assistant tools once (`status`, `list_rooms`, `open_room`, `draft_message`, `read_room`, `open_mini_app`, `send_message`; `src/assistant/mod.rs`). Today the shell reaches them through Rinx's `ServiceExecutor` on the AI services bus. `read_room` asks for a per-room grant on Rinx's read sheet; `send_message` is Destructive and self-confirmed: Rinx's send sheet is the one confirmation. Registering these tools with Rinx's octos peer, so that the peer's own model can call them, needs Rinx to declare them: the kernel's host-registered tools ([octos#2567](https://github.com/octos-org/octos/pull/2567)) are merged and the shell registers and relays each peer's tools ([#145](https://github.com/OctoSense-org/OctoSense/pull/145)), but Rinx declares no `tools.json` yet and has not handed its send sheet to the shell (`OctosAppService::set_confirm_sheet`). +**Tools.** Rinx defines its UI assistant tools in `src/assistant/mod.rs` and exposes them through `ServiceExecutor` on the AI services bus. Reads and sends still use Rinx’s own confirmation sheets. + +The kernel supports host-registered tools, and the shell implements their relay. Rinx has not yet declared those peer tools or registered its send sheet with `OctosAppService::set_confirm_sheet`. Tools available on the AI bus are therefore not automatically available to Rinx’s peer. **Rinx mini apps.** Rinx hosts reviewed OctoScript mini apps and serves them the same four `octos.*` services, each running instance in its own request context of Rinx's peer ([example](https://github.com/hagency-org/Rinx/tree/main/examples/miniapps/matrix-octos-script)). That is Rinx's own mini-app host, for bundles a person imports into Rinx after review; it is not the App Hub install path. @@ -196,7 +204,7 @@ The four `octos.*` calls have separate argument, approval and reply rules: - **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). - **Replies.** The host refuses replies larger than 2 MiB. The response table below lists successful calls and common errors. -So a contained app, store or system, reaches the assistant only through `octos.*`, in a shell that hosts a kernel. What it hears: +A script's own assistant calls use declared `octos.*` services. Separately, the shell can drive an app peer from `agent`/`tools.json` without the script declaring those UI calls. Replies on the script service path: | Call | Answer | | --- | --- | @@ -210,7 +218,7 @@ So a contained app, store or system, reaches the assistant only through `octos.* | `llm.*` from a store app granted `llm` | `llm is for OctoSense's own apps.` | | anything in App Hub's `card-host` | `no service answers "" on this device` (`card-host` registers no services) | -The first row, the `llm` row and the `card-host` row were run in `card-host` (App Hub `362d832`) on 2026-09-27. The reply, the unsupported-arguments answer and the missing-kernel answer were run on macOS on 2026-09-28 in a release desktop with hidden windows, through a system app declaring `octos.session.open` and `octos.turn.start` opened from the launcher; with a kernel built at the then-pinned octos `7bec0918` and the person's provider, the reply came from the peer `card.`, whose memory namespace `app/card./…` appeared in the kernel's data. The text-length and switch-off answers are covered by `cargo test -p octosense-ai-host`, through the same dispatch. OctoScript-App-Design-Flow's [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.md) has the example app and the argument and answer shapes of the four `octos.*` calls as Rinx serves them. +**Historical validation 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. 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). @@ -262,7 +270,7 @@ The tracking issue is [#68](https://github.com/OctoSense-org/OctoSense/issues/68 The log says `octos: kernel service ready (starts on first use), core dir …`. Without `OCTOS_APP_CORE_BIN` it says there is no kernel, and AI providers still saves providers. 3. Open **Start → Settings → AI providers**, add a model (family, model, route, key, **Test connection**, save). The profile is `$T/octos-home/.octos/profiles/_main.json`; with the file vault the key is in it, so delete `$T` afterwards. -4. Use the assistant through a consumer: Rinx (linked by default and in-process; open it from the launcher; sign in to Matrix, allow its agent on the first-use sheet, then use its assistant), or AppCard (`--features app-appcard`). A contained app reaches it through the `octos` host service ([above](#contained-script-apps-system-and-store)); allow the app's agent when the shell asks the first time (or add `OCTOSENSE_CONTAINED_APPS=1` to the command in step 2 to skip the question for every app). +4. Use the assistant through a consumer: Rinx (linked by default and in-process; open it from the launcher; sign in to Matrix, allow its agent on the first-use sheet, then use its assistant), or AppCard (`--features app-appcard`). A contained app reaches it through the `octos` host service ([above](#contained-script-apps-system-and-store)); leave `OCTOSENSE_CONTAINED_APPS` unset and allow the app's agent when the shell asks. F8 also opens the system chat; use `agents.ask` for consent/preparation, then `peer_send_input` for delegation. **Hidden windows.** Add `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=` to drive the shell over the remote bridge without taking the screen ([desktop README § Remote-control bridge](../desktop/README.md#remote-control-bridge)). `desktop/scripts/ai_providers_remote.sh` runs AI providers end to end this way with fake keys and outbound HTTPS denied, and `desktop/scripts/glance_remote.sh` does the same for the glance panel. @@ -280,7 +288,7 @@ OCTOS_APP_PEERS_TEST_KERNEL=/path/to/octos cargo test -p octosense-app-peers --f ### Phone -- **Android (Home):** the Home APK bundles the kernel as `liboctos.so`; `cd phone && python3 ../rom/scripts/build-home.py` builds the APK pair (see [phone/README.md](../phone/README.md)), using [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) at the pinned octos revision. The kernel starts on first use. +- **Android (Home):** the Home APK bundles the kernel as `liboctos.so`. The configured `rom/scripts/build-home.py` pipeline builds the APK pair (see [phone/README.md](../phone/README.md)), using [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) at the locked octos revision. The kernel starts on first use. - Configure providers in **OctoSense Settings → Accounts → AI providers**, or move them from a desktop: **Show QR for phone** on the desktop, then import on the phone by camera, image or pasted code, with the PIN. - **OpenHarmony** runs the kernel in process. **iOS** has no kernel: providers are saved, no app gets an assistant. diff --git a/docs/ai-services.zh-CN.md b/docs/ai-services.zh-CN.md index 7e8fbe5e..b191ab6c 100644 --- a/docs/ai-services.zh-CN.md +++ b/docs/ai-services.zh-CN.md @@ -2,7 +2,9 @@ [English](ai-services.md) | 简体中文 -助手如何接入 OctoSense:Shell 运行的 [octos](https://github.com/octos-org/octos) Agent 内核、用户在哪里配置它、哪些应用可以使用以及如何使用,还有哪些在规划中。本文描述 2026-09-28 的 `main`(OctoSense `ad0d738`,它锁定 octos `5e7577f0` 和 OctoSense-App-Hub `e8601b80`)。标为**目前可用**的内容都在这份代码中读过;**进行中**表示有未合并的 pull request;**规划中**表示只有 ADR 或未关闭的 issue,尚无代码合入。 +本文介绍 OctoSense 的 octos 内核、提供方配置、应用 peer 和工具。状态说明以当前检出为准;阅读外部源码时使用 [Cargo.toml](../Cargo.toml) 的依赖锁定版本。下方带日期的运行信息是历史验证记录。 + +历史源码评审分别在 2026-09-28(OctoSense `ad0d738`)和 2026-09-29(`baa90bd`)进行;这些日期不代表当前状态表的更新时间。 本文讨论的是 OctoSense *内部*的助手。开发应用不需要任何 AI 服务,也不需要特定的编程 Agent:应用开发工具集 [OctoScript-App-Design-Flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow) 适用于任何 Agent,也可以不用 Agent。它的 [AI-SERVICES](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/AI-SERVICES.zh-CN.md) 页面是本文面向应用开发者的简短版本。 @@ -32,10 +34,10 @@ | 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) | | 审批、首次使用同意、开发者模式 | 已实现:Shell 审批路由、常设规则及面板接收 AI 服务总线和内核工具审批;首次运行先征求同意,开发者模式由用户开启 | [架构 § 审批](architecture.zh-CN.md#5-审批) | -| 系统 Agent 的工具集 | 目前可用,已强制:从不提供 octos 的 shell(`_main` profile 的 `tool_policy`,[#117](https://github.com/OctoSense-org/OctoSense/pull/117)),且每次内核启动都设置系统会话的精确内核工具列表(`session/tool_list/set`,octos#2648) | [架构 § 工具与授权](architecture.zh-CN.md#4-工具与授权) | +| 系统 Agent 的工具集 | 已强制:不提供 octos 内置 shell;精确设置系统会话内核工具列表。用户开启命令执行后通过 `terminal.run`,每次命令实时确认;Terminal 可用时模块和进程托管均支持 | [架构 § 工具与授权](architecture.zh-CN.md#4-工具与授权) | | 原生应用只声明一次(`native-apps.json`),按目标平台决定托管方式;Terminal 作为系统应用在桌面端以独立进程运行 | 目前可用([#113](https://github.com/OctoSense-org/OctoSense/pull/113)) | [架构 § 原生应用](architecture.zh-CN.md#原生应用进程内还是独立进程) | | 应用自己的 Agent:声明与执行 | News/Mail/Calendar/Photos/Maps/Camera/YouTube 的 `tools.json`、通用工具授权、peer 和宿主服务执行器已实现。`AGENT.md` 提示词加载、包内 skills/模型选择和自动触发器仍有缺口 | [见下文](#规划中事件驱动的应用-agentadr-0002) | -| 独立进程中的原生应用访问自己的 Agent(peer link,ADR 0004 §5) | 规划中(计划第 8 步)。Makepad 的客户端一侧已合入([OctoSense-org/makepad#54](https://github.com/OctoSense-org/makepad/pull/54),`makepad_ai_services::peer`);Shell 一侧尚未实现(`crates/shell/src/hub.rs` 中没有) | [架构 § 应用与它自己的 Agent](architecture.zh-CN.md#应用与它自己的-agent) | +| 独立进程中的原生应用访问自己的 Agent(peer link) | Makepad 客户端与 Shell `crates/shell/src/peer_link/` 均已实现。当前没有进程应用申请自己的 Agent;Terminal 声明了工具但未申请 peer | [架构 § 应用与它自己的 Agent](architecture.zh-CN.md#应用与它自己的-agent) | ## 架构 @@ -47,7 +49,7 @@ 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"] bus["AI 服务总线
crates/shell/src/ai_bus.rs"] @@ -69,7 +71,7 @@ flowchart TB rinx -- "受限的 OctosAppService" --> broker appcard -- "自己的连接" --> kernel scripts -- "host.request" --> runner - runner -- "octos.* 服务
peer card.<应用 id>" --> broker + runner -- "octos.* 服务
broker 身份 card.<应用 id>" --> broker rinx -- "类型化工具" --> bus bus -- "confirm: host 调用" --> router router --> person @@ -77,18 +79,18 @@ flowchart TB ### octos 内核:每个 Shell 一个 -内核是一个 **Shell 服务**([`crates/kernel`](../crates/kernel/README.md),包名 `octosense-kernel`),不是应用。Shell 在启动时配置一次;在第一个使用者调用 `octosense_kernel::connect()` 之前什么都不运行,之后的使用者共享同一个进程。octos 对它的数据目录持有单写者锁,所以每个 core 目录只有一个内核。最后一个连接关闭时内核停止;`shutdown()` 随 Shell 一起停止它(最多 5 秒)。 +内核是一个 **Shell 服务**([`crates/kernel`](../crates/kernel/README.md),包名 `octosense-kernel`),不是应用。Shell 在启动时配置一次;在第一个使用者调用 `octosense_kernel::connect()` 之前什么都不运行,之后的使用者共享同一个进程。octos 对它的数据目录持有单写者锁,所以每个 core 目录只有一个内核。普通模式下最后一个连接关闭时内核停止;Talk to Octos 开启期间会保持共享内核存活;`shutdown()` 随 Shell 一起停止它(最多 5 秒)。 各平台的运行方式(`crates/kernel/src/launch.rs`,`crates/ai-host` 中的 `KernelSource::platform()`): | 平台 | 内核 | Core 目录(octos home) | | --- | --- | --- | -| 桌面端(macOS;Windows 和 Linux 未测试) | `$OCTOS_APP_CORE_BIN serve --stdio --data-dir `(存在 `/config.json` 时再加 `--config`)。**没有 `OCTOS_APP_CORE_BIN` 就没有内核**,开发者自己运行的 `octos serve` 永远不会被动到。把内核打包在桌面端二进制旁边的工作正在进行([#85](https://github.com/OctoSense-org/OctoSense/pull/85))。 | `$OCTOS_APP_CORE_DIR`,否则为 `/octos-home/.octos`(`~/.octosense/octos-home/.octos`):OctoSense 自己的目录,不再是用户的 `~/octos-home/.octos`(只从中复制一次提供商设置) | +| 桌面端(macOS;Windows 和 Linux 未测试) | `$OCTOS_APP_CORE_BIN serve --stdio --data-dir `(存在 `/config.json` 时再加 `--config`)。**未显式指定内核程序或 `OCTOS_APP_CORE_BIN` 时没有桌面内核**,开发者自己运行的 `octos serve` 永远不会被动到。[#85](https://github.com/OctoSense-org/OctoSense/pull/85) 是内核打包的历史跟踪;此配方显式指定二进制。 | `$OCTOS_APP_CORE_DIR`,否则为 `/octos-home/.octos`(`~/.octosense/octos-home/.octos`):OctoSense 自己的目录,不再是用户的 `~/octos-home/.octos`(只从中复制一次提供商设置) | | Android(Home) | APK 中的 `liboctos.so serve --stdio`,由 [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) 按根 `Cargo.toml` 锁定的 octos 版本构建 | `<应用数据目录>/octos-home/.octos` | | OpenHarmony | 进程内运行(`octos_cli::embedded::serve_io`),因为 HAP 不能 exec | `<应用数据目录>/octos-home/.octos` | | iOS | **没有。** 提供方仍会保存;没有应用能获得助手 | – | -使用者通过 `Connection` 使用 octos UI Protocol(JSON-RPC 帧,与 `octos serve --stdio` 相同)。每个使用者只收到自己请求的回复和自己会话的通知。提供方变更时内核重启,所有连接以 `CloseReason::Restarted` 结束;使用者重新连接并重新打开会话(AppCard 的传输层是参考实现)。 +开启 Talk to Octos 后,内核使用宿主管理的回环 WebSocket 代替 stdio。使用者通过 `Connection` 使用 octos UI Protocol(JSON-RPC 帧,与 `octos serve --stdio` 相同)。每个使用者只收到自己请求的回复和自己会话的通知。提供方变更时内核重启,所有连接以 `CloseReason::Restarted` 结束;使用者重新连接并重新打开会话(AppCard 的传输层是参考实现)。 ### AI providers 与 `llm` 宿主服务 @@ -125,15 +127,19 @@ flowchart TB [`crates/app-peers`](../crates/app-peers/README.md) 是应用和内核之间的中介(Rinx [ADR 0007](https://github.com/hagency-org/Rinx/blob/main/docs/adr/0007-host-owned-octos-app-peers.md);内核一侧是 octos UPCR-2026-034): -- 原生模块声明的 `octos.*` 服务获得策略授权后,该应用会在 Shell 的内核上得到**一个 octos peer**,通过 `peer/prepare` 创建或恢复。没有获得任何授权的模块不会分配 peer。 +- 原生模块声明的 `octos.*` 服务获得策略授权后,该应用会在 Shell 的内核上得到**每个账号一个 octos peer**,通过 `peer/prepare` 创建或恢复。没有获得任何授权的模块不会分配 peer。 - peer 的**所有者**是 Shell 的系统 Agent 会话 `_main:api:octosense#system`。内核为 peer 生成宿主 token;Shell 把它保存在 `/../app-peers`(0600),任何应用都无法访问。 -- peer 的**记忆命名空间**是 `app//acct-`:按应用和应用账号区分(hash 是账号 id 的非机密标签)。内核为它提供工作区。不支持这一约定的内核会被拒绝,绝不会退回到使用配置共享记忆的普通会话。 -- 应用永远看不到内核协议。它为正在创建的实例拿到一个受限的 `OctosAppService`,绑定已登录的账号,并为每个客户端实例打开一个**请求上下文**(`peer/context/open`)。切换账号会撤销旧账号的所有上下文;迟到的事件会被丢弃。 -- 操作包括 `Open`、`History`、`Turn { text }`、`Interrupt` 和 `Approval { id, approve }`,每个都受对应的精确服务名约束(`octos.session.open`、`octos.session.history`、`octos.turn.start`、`octos.turn.interrupt`;审批需要 `octos.turn.start`)。一个回合 180 秒后超时。 +- peer 的**记忆命名空间**是 `app//acct-`:按应用和应用账号区分(hash 是账号 id 的非机密标签)。Shell 选择获准的账号工作目录,内核创建并核验。不支持这一约定的内核会被拒绝,绝不会退回到使用配置共享记忆的普通会话。 +- 应用永远看不到内核协议。它为正在创建的实例拿到一个受限的 `OctosAppService`,绑定已登录的账号,并为每个客户端实例打开一个**请求上下文**(`peer/context/open`)。请求上下文是同一 peer 下独立的内核 session,不是另一个应用 peer。`open_conversation` 创建带有限共享历史的人类通道,peer session 处理系统委派。切换账号会撤销旧账号的所有上下文;迟到的事件会被丢弃。 +- 操作包括 `Open`、`History`、`Turn { text }`、`Interrupt` 和 `Approval { id, approve }`,每个都受对应的精确服务名约束(`octos.session.open`、`octos.session.history`、`octos.turn.start`、`octos.turn.interrupt`;审批需要 `octos.turn.start`)。broker 默认回合超时为 180 秒。 ### 系统 Agent -目前系统 Agent 是所有应用 peer 的**所有者**:创建它们并能与之通信的会话。它不持有任何应用的工具,也无法回答应用 peer 的审批(octos [#2560](https://github.com/octos-org/octos/pull/2560))。它的工具是 Shell 在每次启动内核前写入的一个确定集合,从不提供 octos 的 shell([#117](https://github.com/OctoSense-org/OctoSense/pull/117),`crates/kernel/src/system_tools.rs`;见[架构 § 工具与授权](architecture.zh-CN.md#4-工具与授权))。目前用户通过 Talk to Octos 客户端与它对话([#98](https://github.com/OctoSense-org/OctoSense/pull/98),[ADR 0003](adr/0003-shared-octos-client-access.md));Shell 还没有为它绘制自己的对话界面。它在 ADR 0002 中更大的角色(监督应用 Agent、预算、紧急停止、对 glance 屏幕排序、改进应用 Agent)还在**规划中**;glance 屏幕目前按优先级和时间排序卡片。 +系统 Agent 拥有应用 peer,通过 `peer_send_input` 委派任务,再用 `peer_gather` 获取结果。`agents.list` 发现应用 Agent;`agents.ask` 请求首次同意并准备 peer,本身不发送委派任务。 + +用户可用 F8 或 Shell 的 Assistant 入口打开系统聊天(`crates/shell/src/system_chat/`),也可通过桌面 “Ask <app>” 面板或卡片 `sys.chat` 直接与应用 Agent 对话;手机尚无打开 Ask-app 面板的触控入口。 + +系统 Agent 使用受限内核工具列表和审核过的 Shell 工具(例如需开启的 `terminal.run`),不会继承所有应用工具,也不能替用户审批。Talk to Octos 是另一种客户端入口。自动触发调度、学习 overlay 和更丰富的 glance 排序仍在规划中;卡片目前按优先级和时间排序。 ### Shell 中的其他助手 @@ -146,8 +152,8 @@ flowchart TB | --- | --- | | **密钥留在宿主。** | 只有 `llm` 服务读写密钥;密钥保存在平台密钥存储或内核 core 目录下仅所有者可读的配置中,从不进入应用的 jail。app-peers 约定中不携带任何凭据(`ModelInfo` 中没有)。没有任何 `octos.*` 服务允许应用选择提供方或提交密钥。 | | **机密归宿主所有。** | 应用不收集密码、PIN、密钥或一次性验证码,即使只是转交也不行。运行时让受管控隔离环境中的密码输入框失效,App Hub 的准入检查拒绝声明了此类输入框的应用包,服务在自己的面板上询问(`.sheet.*` 只接受来自面板的调用)。 | -| **审批属于用户,在所属应用中进行。** | 应用上下文中发起的工具审批只能由该应用自己的界面通过 `ContextOp::Approval` 回答;系统 Agent 从不替应用审批(app-peers 策略,octos #2560)。Rinx 的 `send_message` 会在 Rinx 自己的面板上显示房间和确切文字,只有用户确认才发送。Shell 的审批路由([#120](https://github.com/OctoSense-org/OctoSense/pull/120))只凭用户的操作作答:在 Shell 绘制的面板上当场确认,或按用户自己建立的常设规则;“我的联系人”类规则只有在用户打开“在审批规则中使用我的联系人”之后才会使用联系人([架构 § 审批](architecture.zh-CN.md#5-审批))。开发者模式为它覆盖的应用回答所有审批,只能由用户打开([#118](https://github.com/OctoSense-org/OctoSense/pull/118))。 | -| **系统 Agent 通过应用的 Agent 驱动应用。** | 它拥有 peer,但不持有应用工具;应用的工具在应用中运行(Rinx:`src/assistant`,“系统 Agent 自己从不持有这些工具,而是请求 Rinx 的 peer”)。 | +| **审批属于用户。** | Shell 将 `host_tool` 以及其他内核工具审批交给宿主路由,应用只收到 `approval/handled_by_host`。`confirm: app` 使用明确注册的所属应用面板。系统 Agent 不能代替用户同意;常设规则和开发者模式由用户控制,仍受工具限制,例如 Terminal 命令不能自动批准。见[审批](architecture.zh-CN.md#5-审批)。 | +| **委派和工具执行的权限不同。** | 系统 Agent 委派给应用 peer;relay 检查授权、schema 和策略后以所有者身份执行工具。跨应用工具授权必须明确,不是获得所有 API 或数据库;系统会话另有审核过的 Shell 工具,如 `terminal.run`。 | | **记忆按应用和账号私有。** | 每个 peer 的记忆命名空间是 `app//acct-`;一个账号的上下文从不在另一个账号下恢复。提升到共享记忆还在规划中(ADR 0002 §9)。 | | **最小权限,按精确名称。** | 应用得到的是 `声明 ∩ 支持 ∩ 宿主策略` 的服务,按精确名称比较:`octos.` 或 `octos.admin` 不授予任何权限。 | @@ -173,7 +179,7 @@ flowchart TB 4. `availability()` 报告 `Unavailable`(没有内核、未授权、未登录)、`Idle`、`Ready` 或 `Failed`;在任何状态下应用的普通界面都照常工作。`settings_entry()` 为 `Host`:应用不提供自己的提供方表单,而是引导用户去 AI providers。 -**工具。** Rinx 只定义一次它的助手工具(`status`、`list_rooms`、`open_room`、`draft_message`、`read_room`、`open_mini_app`、`send_message`;`src/assistant/mod.rs`)。目前 Shell 通过 AI 服务总线上 Rinx 的 `ServiceExecutor` 调用它们。`read_room` 会在 Rinx 的读取面板上请求按房间的授权;`send_message` 是 Destructive 且自行确认:Rinx 的发送面板就是唯一的一次确认。把这些工具注册到 Rinx 的 octos peer、让 peer 自己的模型能调用它们,要等内核支持宿主注册工具([octos#2567](https://github.com/octos-org/octos/pull/2567),尚未合并)。 +**工具。** Rinx 在 `src/assistant/mod.rs` 定义其 UI 助手工具,通过 AI 服务总线上的 `ServiceExecutor` 执行,读取和发送仍走自己的确认界面。内核宿主注册工具及 Shell relay 已实现,缺口不是等待 octos#2567 合并:当前 Rinx 原生清单未声明这些 peer 工具,也尚未通过 `OctosAppService::set_confirm_sheet` 将发送确认面板交给 Shell。因此不要把总线上能调用的工具当作 Rinx peer 已拥有的工具。 **Rinx 迷你应用。** Rinx 托管经过审核的 OctoScript 迷你应用,并向它们提供同样的四个 `octos.*` 服务,每个运行中的实例使用 Rinx peer 的一个独立请求上下文([示例](https://github.com/hagency-org/Rinx/tree/main/examples/miniapps/matrix-octos-script))。这是 Rinx 自己的迷你应用宿主,适用于用户审核后导入 Rinx 的应用包;它不是 App Hub 的安装路径。 @@ -196,7 +202,7 @@ flowchart TB - **工具审批。** peer 的工具请求交给 Shell 的审批路由及其面板(ADR 0004 §8)。开发者模式会为它覆盖的应用作答。没有审批路由的宿主会拒绝请求,并在 `denied_approvals` 中列出。详见 [`host_approvals.rs`](../crates/app-peers/src/host_approvals.rs)。 - **回复。** 宿主拒绝超过 2 MiB 的回复。下表列出成功调用及常见错误的返回内容。 -因此,隔离运行的应用(商店应用或系统应用)只能通过 `octos.*` 使用助手,且需要 Shell 托管了内核。它会收到: +脚本自己的助手调用使用已声明的 `octos.*`;Shell 也可以根据 `agent`/`tools.json` 驱动 peer,而不要求脚本声明这些 UI 调用。脚本服务调用的回复: | 调用 | 返回 | | --- | --- | @@ -210,7 +216,7 @@ 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)。 @@ -262,7 +268,7 @@ App Hub 接受 manifest 的 `agent` 设置,并按自己的限制裁剪。Shell 日志中会出现 `octos: kernel service ready (starts on first use), core dir …`。没有 `OCTOS_APP_CORE_BIN` 时日志会说明没有内核,AI providers 仍会保存提供方。 3. 打开 **Start → Settings → AI providers**,添加一个模型(family、模型、路由、密钥、**Test connection**、保存)。配置文件是 `$T/octos-home/.octos/profiles/_main.json`;使用文件密钥库时密钥就在其中,用完后请删除 `$T`。 -4. 通过某个使用者来使用助手:Rinx(默认链接并在进程内运行;从启动器打开它;登录 Matrix,在首次使用面板上允许它的 Agent,然后使用它的助手),或 AppCard(`--features app-appcard`)。隔离运行的应用通过 `octos` 宿主服务访问它([见上文](#隔离运行的脚本应用系统应用和商店应用));在 Shell 第一次询问时允许该应用的 Agent(或在第 2 步的命令中加上 `OCTOSENSE_CONTAINED_APPS=1`,对所有应用跳过这个询问)。 +4. 通过某个使用者来使用助手:Rinx(默认链接并在进程内运行;从启动器打开它;登录 Matrix,在首次使用面板上允许它的 Agent,然后使用它的助手),或 AppCard(`--features app-appcard`)。隔离运行的应用通过 `octos` 宿主服务访问它([见上文](#隔离运行的脚本应用系统应用和商店应用));保持 `OCTOSENSE_CONTAINED_APPS` 未设置,并在 Shell 询问时同意。F8 也可打开系统聊天;`agents.ask` 用于同意/准备,`peer_send_input` 才委派任务。 **隐藏窗口。** 加上 `MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE=`,即可通过远程控制桥操作 Shell 而不占用屏幕([桌面端 README § Remote-control bridge](../desktop/README.md#remote-control-bridge))。`desktop/scripts/ai_providers_remote.sh` 以这种方式端到端运行 AI providers,使用假密钥并禁止出站 HTTPS;`desktop/scripts/glance_remote.sh` 对 glance 面板做同样的事。 @@ -280,7 +286,7 @@ OCTOS_APP_PEERS_TEST_KERNEL=/path/to/octos cargo test -p octosense-app-peers --f ### 手机 -- **Android(Home):** Home APK 把内核打包为 `liboctos.so`;`cd phone && python3 ../rom/scripts/build-home.py` 构建这对 APK(见 [phone/README.md](../phone/README.md)),其中使用 [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) 按锁定的 octos 版本构建内核。内核在首次使用时启动。 +- **Android(Home):** Home APK 把内核打包为 `liboctos.so`;配置好参数的 `rom/scripts/build-home.py` 流水线构建 APK 对(见 [phone/README.md](../phone/README.md)),其中使用 [`tools/kernel-artifact.py`](../tools/kernel-artifact.py) 按锁定的 octos 版本构建内核。内核在首次使用时启动。 - 在 **OctoSense Settings → Accounts → AI providers** 中配置提供方,或者从桌面端迁移:在桌面端点 **Show QR for phone**,然后在手机上通过相机、图片或粘贴代码导入,并输入 PIN。 - **OpenHarmony** 在进程内运行内核。**iOS** 没有内核:提供方会被保存,但没有应用能获得助手。