Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
| A system app's agent: its tools and the cards they publish | `apps/<name>/bundle/tools.json` and the manifest's `agent` block; the tools run on the app's host service | its host service's tests (below); then in a shell, with the system agent asking the app's agent |
| A host service (`mail`, `calendar`, `news`, `llm`, `model`) | `apps/mail/host-service/`, `apps/calendar/host-service/`, `apps/news/host-service/`, `apps/ai-providers/` (`llm` and `model.complete`) | `cargo test --locked -p octosense-mail-service -p octosense-calendar-service -p octosense-news-service -p octosense-llm-service` |
| AppCard (opt-in) | `apps/appcard/` | [apps/appcard/AGENTS.md](apps/appcard/AGENTS.md), `apps.yml` |
| A native app (App Hub, Rinx, Terminal, Sheets, Reference, AppCard): its crate, pin, features, hosting per target, sandbox, storage and agent grants | `native-apps.json` only; `python3 tools/native_apps.py` writes the marked blocks in the `Cargo.toml`s, `crates/shell/src/native_apps.rs` and `Cargo.lock` | `python3 tools/native_apps.py --check`, `python3 -m unittest discover -s tools -p 'test_*.py'` |
| A native app (App Hub, Rinx, Terminal, Sheets, Reference, AppCard, and the Makepad apps made native: Calculator, Clock, Notes, Reminders, Weather, and Task, which runs only as its own process): its crate, pin, features, hosting per target, sandbox, storage, its tools and which of them the system agent may call (`agent.system_tools`) | `native-apps.json` only; `python3 tools/native_apps.py` writes the marked blocks in the `Cargo.toml`s, `crates/shell/src/native_apps.rs` and `Cargo.lock` | `python3 tools/native_apps.py --check`, `python3 -m unittest discover -s tools -p 'test_*.py'` |
| An external pin (Makepad, OctoScript, App Hub, octos, Rinx) | root `Cargo.toml` `[workspace.dependencies]` (a native app's in `native-apps.json`), `native-runtime.lock.json`, `runtime-patches.lock.json` | `python3 tools/setup.py --update`, then `--check --cargo` and `python3 tools/native_apps.py --check` |
| A decision | `docs/adr/` (next free number) | — |

Expand Down
83 changes: 83 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ makepad-sheets = { git = "https://github.com/OctoSense-org/makepad.git", rev = "
makepad-terminal = { git = "https://github.com/OctoSense-org/makepad.git", rev = "c155f61d0e1600d2ec474209374444a38a09a470" }
octosense-appcard = { path = "apps/appcard/module" }
octosense-app-hub-app = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "0d5b47a2ae9eb98020feca26b7c895a3cf797dc1" }
makepad-calculator = { git = "https://github.com/OctoSense-org/makepad.git", rev = "c155f61d0e1600d2ec474209374444a38a09a470", default-features = false }
makepad-clock = { git = "https://github.com/OctoSense-org/makepad.git", rev = "c155f61d0e1600d2ec474209374444a38a09a470", default-features = false }
makepad-notes = { git = "https://github.com/OctoSense-org/makepad.git", rev = "c155f61d0e1600d2ec474209374444a38a09a470", default-features = false }
makepad-reminders = { git = "https://github.com/OctoSense-org/makepad.git", rev = "c155f61d0e1600d2ec474209374444a38a09a470", default-features = false }
makepad-weather = { git = "https://github.com/OctoSense-org/makepad.git", rev = "c155f61d0e1600d2ec474209374444a38a09a470", default-features = false }
makepad-task = { git = "https://github.com/OctoSense-org/makepad.git", rev = "c155f61d0e1600d2ec474209374444a38a09a470" }
# END native-apps: pins
# --- Makepad (OctoSense-org/makepad), the revision Octoscript-Makepad's
# runtime.json pins (native-runtime.lock.json); resolved to .sources/makepad.
Expand Down Expand Up @@ -236,6 +242,12 @@ makepad-markdown-widgets = { path = ".sources/makepad/libs/markdown_widgets" }
# BEGIN native-apps: patch https://github.com/OctoSense-org/makepad.git (generated by tools/native_apps.py from native-apps.json; do not edit)
makepad-sheets = { path = ".sources/makepad/apps/sheets" }
makepad-terminal = { path = ".sources/makepad/apps/terminal" }
makepad-calculator = { path = ".sources/makepad/apps/calculator" }
makepad-clock = { path = ".sources/makepad/apps/clock" }
makepad-notes = { path = ".sources/makepad/apps/notes" }
makepad-reminders = { path = ".sources/makepad/apps/reminders" }
makepad-weather = { path = ".sources/makepad/apps/weather" }
makepad-task = { path = ".sources/makepad/apps/task" }
# END native-apps: patch https://github.com/OctoSense-org/makepad.git

# AppCard's inline-renderer kits name makepad-widgets by the ZhangHanDong URL.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ The person talks to it in the shell's **assistant pane**, the system chat (`crat

Its kernel tools are exactly `SYSTEM_AGENT_TOOLS` (`crates/kernel/src/system_tools.rs`): `peer_send_input`, `peer_gather`, `peer_list` and `peer_respond` to supervise app agents, its workspace's file tools, memory, `ask_user_question`, media viewing, `web_search`, `web_fetch` and `tool_search`. Every kernel start sets that list with octos's `session/tool_list/set`, so octos's own shell, the spawn family and `peer_close` are never offered.

The system chat also registers host tools on the session: `agents.list` and `agents.ask` (`crates/shell/src/agents.rs`: which apps have an agent, and the first-use sheet and ready-peer wait for one), and `terminal.run` while Setup › Assistant › Command execution is on.
The system chat also registers host tools on the session: `agents.list` and `agents.ask` (`crates/shell/src/agents.rs`: which apps have an agent, and the first-use sheet and ready-peer wait for one), `terminal.run` while Setup › Assistant › Command execution is on, and the native apps' own read tools their `native-apps.json` entries name (`agent.system_tools`): Calculator's `calculator.eval`, Clock's `clock.now`, Notes' `notes.search` and `notes.read`, Reminders' `reminders.due` and `reminders.list`, Weather's `weather.current`. Such a call reaches the app's open instance (its AI bus service); a closed app answers "Open Notes first".

**An app agent** is one host-owned octos peer per (app, account) ([`crates/app-peers`](crates/app-peers/README.md)). These apps have one on `main` (`crates/shell/src/apps.rs`, `agent_apps`):

Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ flowchart LR

它的内核工具恰好是 `SYSTEM_AGENT_TOOLS`(`crates/kernel/src/system_tools.rs`):用于监督应用 Agent 的 `peer_send_input`、`peer_gather`、`peer_list` 和 `peer_respond`,其工作区的文件工具,记忆,`ask_user_question`,媒体查看,`web_search`、`web_fetch` 和 `tool_search`。每次内核启动都用 octos 的 `session/tool_list/set` 设置这份列表,所以 octos 自带的 shell、spawn 一族和 `peer_close` 永远不会提供给它。

系统对话还会在这个会话上注册宿主工具:`agents.list` 和 `agents.ask`(`crates/shell/src/agents.rs`:哪些应用有 Agent,以及某个 Agent 的首次使用面板与就绪等待),以及在 Setup › Assistant › Command execution 打开期间的 `terminal.run`。
系统对话还会在这个会话上注册宿主工具:`agents.list` 和 `agents.ask`(`crates/shell/src/agents.rs`:哪些应用有 Agent,以及某个 Agent 的首次使用面板与就绪等待),在 Setup › Assistant › Command execution 打开期间的 `terminal.run`,以及原生应用在 `native-apps.json` 条目中列出的只读工具(`agent.system_tools`):Calculator 的 `calculator.eval`、Clock 的 `clock.now`、Notes 的 `notes.search` 和 `notes.read`、Reminders 的 `reminders.due` 和 `reminders.list`、Weather 的 `weather.current`。这样的调用会到达该应用已打开的实例(它的 AI bus 服务);应用未打开时会回答“Open Notes first”。

**应用 Agent** 是每个(应用,账号)一个由宿主拥有的 octos peer([`crates/app-peers`](crates/app-peers/README.md))。`main` 上以下应用有 Agent(`crates/shell/src/apps.rs`,`agent_apps`):

Expand Down
5 changes: 5 additions & 0 deletions crates/ai-host/src/native_agents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@
/// (app id, the `octos.*` services its agent is granted).
pub const NATIVE_AGENTS: &[(&str, &[&str])] = &[
("rinx", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("calculator", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("clock", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("notes", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("reminders", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
("weather", &["octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt"]),
];
20 changes: 11 additions & 9 deletions crates/ai-host/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,23 +104,25 @@ fn rinx_is_granted_before_start() {
assert!(offered.finish().is_some());
}

/// The shipped policy grants Rinx exactly the assistant services, and it
/// comes from `native-apps.json` (the generated `native_agents`), not code.
/// The shipped policy grants each native app the agent services its
/// `native-apps.json` entry declares (the generated `native_agents`), not
/// code: Rinx exactly the assistant services.
#[test]
fn the_shipped_policy_grants_rinx_the_assistant() {
fn the_shipped_policy_grants_each_native_app_its_declared_services() {
let policy = Policy::shipped();
let grants: Vec<_> = policy.grants().collect();
assert_eq!(grants.len(), 1);
assert_eq!(grants[0].0, "rinx");
assert_eq!(grants[0].1, octosense_app_peers::OCTOS_SERVICES.map(String::from));
let rinx = grants.iter().find(|(app, _)| *app == "rinx").expect("Rinx is granted");
assert_eq!(rinx.1, octosense_app_peers::OCTOS_SERVICES.map(String::from));
assert!(Policy::none().grants().next().is_none());
let generated: Vec<(&str, Vec<String>)> = crate::native_agents::NATIVE_AGENTS.iter().map(|(app, s)| (*app, s.iter().map(|s| s.to_string()).collect())).collect();
let shipped: Vec<(&str, Vec<String>)> = policy.grants().map(|(app, s)| (app, s.to_vec())).collect();
assert_eq!(shipped, generated, "Policy::shipped() is the manifest's agent block");
let manifest: serde_json::Value = serde_json::from_str(include_str!("../../../native-apps.json")).unwrap();
let rinx = manifest["apps"].as_array().unwrap().iter().find(|a| a["id"] == "rinx").unwrap();
let declared: Vec<String> = rinx["agent"]["octos"].as_array().unwrap().iter().map(|s| s.as_str().unwrap().to_string()).collect();
assert_eq!(grants[0].1, declared);
for (app, services) in &grants {
let entry = manifest["apps"].as_array().unwrap().iter().find(|a| a["id"] == *app).unwrap();
let declared: Vec<String> = entry["agent"]["octos"].as_array().unwrap().iter().map(|s| s.as_str().unwrap().to_string()).collect();
assert_eq!(services.to_vec(), declared, "{app}");
}
}

#[test]
Expand Down
6 changes: 6 additions & 0 deletions crates/process-apps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@ path = "src/lib.rs"
octosense-reference = { workspace = true }
makepad-sheets = { workspace = true, features = ["standalone"] }
makepad-terminal = { workspace = true }
makepad-calculator = { workspace = true, features = ["standalone"] }
makepad-clock = { workspace = true, features = ["standalone"] }
makepad-notes = { workspace = true, features = ["standalone"] }
makepad-reminders = { workspace = true, features = ["standalone"] }
makepad-weather = { workspace = true, features = ["standalone"] }
makepad-task = { workspace = true }
# END native-apps: process deps
10 changes: 10 additions & 0 deletions crates/shell/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ makepad-sheets = { workspace = true, optional = true }
makepad-terminal = { workspace = true, optional = true }
octosense-appcard = { workspace = true, optional = true }
octosense-app-hub-app = { workspace = true, optional = true }
makepad-calculator = { workspace = true, optional = true }
makepad-clock = { workspace = true, optional = true }
makepad-notes = { workspace = true, optional = true }
makepad-reminders = { workspace = true, optional = true }
makepad-weather = { workspace = true, optional = true }
# END native-apps: deps

# The host secrets API keeps apps' secrets in the keychain (app_storage/secrets.rs).
Expand Down Expand Up @@ -116,6 +121,11 @@ app-sheets = ["dep:makepad-sheets"]
app-terminal = ["dep:makepad-terminal"]
app-appcard = ["dep:octosense-appcard", "octos-core"]
app-hub = ["dep:octosense-app-hub-app", "dep:octosense-appstore", "dep:octosense-app-policy", "dep:octosense-app-hub", "dep:octosense-app-contract", "dep:octosense-mail-service", "dep:octosense-news-service", "dep:octosense-calendar-service", "octosense-ai-host/llm"]
app-calculator = ["dep:makepad-calculator"]
app-clock = ["dep:makepad-clock"]
app-notes = ["dep:makepad-notes"]
app-reminders = ["dep:makepad-reminders"]
app-weather = ["dep:makepad-weather"]
# END native-apps: features
# The aichat module, seated in the pane in-process.
app-aichat = ["dep:makepad-aichat"]
Expand Down
26 changes: 25 additions & 1 deletion crates/shell/src/apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,17 @@ pub fn catalog_visible(id: &str) -> bool {
!matches!(id, "card" | "appstore")
}

/// Registry rows a shell surface launches but no list shows as an app:
/// `aichat` is the assistant pane's own process (F10), which the pane
/// starts (`clients::find_app("aichat")`); the dock and the launcher do not.
pub const PANE_ONLY: &[&str] = &["aichat"];

/// Whether a registry row is listed to the person and the system agent:
/// the launcher, the dock, the phone's home, the `os` app list.
pub fn listed(id: &str) -> bool {
catalog_visible(id) && !PANE_ONLY.contains(&id)
}

/// The linked modules as launcher rows.
pub fn bundled_modules_catalog() -> Vec<crate::clients::AppDef> {
linked_modules()
Expand Down Expand Up @@ -504,7 +515,9 @@ pub fn is_launchable(app: &crate::clients::AppDef) -> bool {
pub fn manifest_default(declared: crate::native_apps::Hosting, process_form: impl FnOnce() -> bool, vulkan_wayland: bool) -> Hosting {
use crate::native_apps::Hosting as Declared;
let wants_process = match declared {
Declared::Module => false,
// `None` is a process-only app's where it cannot run; nothing links
// such an app, so it never reaches here as a module.
Declared::Module | Declared::None => false,
Declared::Process => true,
Declared::ProcessIfVulkan => vulkan_wayland,
};
Expand Down Expand Up @@ -650,6 +663,17 @@ impl AppRegistry {

#[cfg(test)]
mod tests {
/// The assistant pane's own process is a registry row (F10 starts it
/// from there) but no list shows it as an app; the apps people pick
/// are listed.
#[test]
fn the_panes_own_process_is_never_listed_as_an_app() {
assert!(!listed("aichat"));
assert!(!listed("card") && !listed("appstore"));
assert!(listed("notes") && listed("terminal") && listed("os.mail"));
assert!(crate::shell::launcher::apps().iter().all(|a| a.id != "apps.aichat" && a.id != "aichat"));
}

use super::*;

/// ADR 0004 §3: no script app takes a native app's id or namespace.
Expand Down
6 changes: 3 additions & 3 deletions crates/shell/src/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ pub fn adopt_legacy_homes_later(layout: &crate::app_storage::Layout) {
} else {
Hosting::Module
};
if matches!(hosting, Hosting::Module) {
if matches!(hosting, Hosting::Module | Hosting::None) {
continue;
}
if let Ok(paths) = layout.app(app.id) {
Expand Down Expand Up @@ -1777,7 +1777,7 @@ mod tests {
#[test]
fn makepad_launches_build_outside_cargos_checkout() {
let apps = crate::octosense::catalog::parse_catalog(
br#"[{"id":"browser","label":"Browser","source":"makepad","package":"makepad-browser","bin":"browser"}]"#,
br#"[{"id":"example","label":"Example","source":"makepad","package":"makepad-example","bin":"example"}]"#,
Path::new("/catalog"),
Some(Path::new("/cargo/checkouts/makepad-d00a/ad8f372")),
)
Expand All @@ -1787,7 +1787,7 @@ mod tests {
assert!(build.args.windows(2).any(|p| p == ["--manifest-path", "/cargo/checkouts/makepad-d00a/ad8f372/Cargo.toml"]));
let at = build.args.iter().position(|arg| arg == "--target-dir").expect("builds are redirected out of the cargo cache");
assert!(!build.args[at + 1].starts_with("/cargo/checkouts"), "{}", build.args[at + 1]);
assert_eq!(plan.program, build.target_dir.join("release").join(exe_name("browser")));
assert_eq!(plan.program, build.target_dir.join("release").join(exe_name("example")));
assert_eq!(build.dir, Path::new("/cargo/checkouts/makepad-d00a/ad8f372"), "cargo runs in its checkout");
}

Expand Down
Loading
Loading