Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions console/Cargo.lock

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

1 change: 1 addition & 0 deletions console/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
clap = { version = "4", features = ["derive", "env"] }
schemars = "0.8"
uuid = { version = "1", features = ["v4"] }
async-trait = "0.1"
url = "2"
sha2 = "0.10"
Expand Down
11 changes: 8 additions & 3 deletions console/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,18 @@ Light and dark themes via `data-theme` + CSS custom properties. Persisted to `lo

### Worker SDK surface

`console` registers a single function against the engine for health probes and `iii worker info` smoke tests:
`console` registers a health probe for `iii worker info` smoke tests, plus the workspace functions that let an agent show the human a screen next to the conversation:

| Function | Input | Output |
|---|---|---|
| `console::status` | `{}` | `{ http_port, engine_url, version }` |
| `console::workspace::list` | `{}` | `{ tabs: [{ id, name?, columns, screens, active }], active_tab_id }` |
| `console::workspace::open` | `{ screen, activate? }` | `{ tab_id, column, placement, screens, activated }` |
| `console::workspace::close` | `{ screen }` | `{ tab_ids }` |

Defined in [`src/functions/status.rs`](src/functions/status.rs).
A screen is `chat`, `traces`, `workers`, or `ext:<page-id>` for a worker page (`ext:shell`, `ext:browser`, `ext:editor`, ...). The workspace layout is the `workspace` section of the `console` configuration entry, so every browser pointed at this engine picks the change up. `open` stays on the active tab when it already shows the screen, else switches to the tab that does, else places the screen beside chat in the active tab (adjacent empty column, any empty column, new column), else opens a fresh chat + screen tab; `placement` reports which (`existing`, `empty_column`, `new_column`, `new_tab`). It never replaces a mounted screen. `close` detaches the screen everywhere it is mounted and is idempotent. Unknown screens fail with `WORKSPACE_INVALID_SCREEN`; an unreachable configuration worker with `WORKSPACE_UNAVAILABLE`.

Defined in [`src/functions/status.rs`](src/functions/status.rs) and [`src/functions/workspace.rs`](src/functions/workspace.rs).

## Architecture

Expand All @@ -174,7 +179,7 @@ flowchart LR
Browser -->|"HTTP GET /runtime"| Console
Browser -->|"WS /ws"| Console
Console["console binary<br/>(axum + rust-embed)"] -->|"WebSocket"| Engine["iii engine<br/>:49134"]
Console -. "registers console::status" .-> Engine
Console -. "registers console::status, console::workspace::*" .-> Engine
```

`console` is a thin HTTP server. It serves the embedded SPA bundle and
Expand Down
15 changes: 13 additions & 2 deletions console/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ pub struct ConfigChangeAck {
pub struct ConfigChangeRequest {}

/// `Ok(None)` when the entry does not exist or holds `null`.
async fn existing_value(iii: &IIIClient) -> Result<Option<Value>, String> {
pub(crate) async fn existing_value(iii: &IIIClient) -> Result<Option<Value>, String> {
match trigger_configuration_with_retry(iii, "configuration::get", json!({ "id": config_id() }))
.await
{
Expand All @@ -293,7 +293,18 @@ async fn existing_value(iii: &IIIClient) -> Result<Option<Value>, String> {
}
}

async fn trigger_configuration_with_retry(
/// Replace the stored `console` entry wholesale (`configuration::set`).
pub(crate) async fn set_value(iii: &IIIClient, value: Value) -> Result<(), String> {
trigger_configuration_with_retry(
iii,
"configuration::set",
json!({ "id": config_id(), "value": value }),
)
.await
.map(|_| ())
}

pub(crate) async fn trigger_configuration_with_retry(
iii: &IIIClient,
function_id: &str,
payload: Value,
Expand Down
12 changes: 9 additions & 3 deletions console/src/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
//!
//! `console` is mostly an HTTP server + WS proxy, so the SDK surface is
//! deliberately small: one health/identity function (`console::status`)
//! that returns the runtime knobs the worker booted with, plus the
//! injectable-UI debug surface (`console::ui-manifest`).
//! that returns the runtime knobs the worker booted with, the
//! injectable-UI debug surface (`console::ui-manifest`), and the workspace
//! layout functions (`console::workspace::*`) that let an agent show a
//! screen to the human.

pub mod status;
pub mod workspace;

use std::sync::Arc;

Expand All @@ -30,7 +33,10 @@ pub fn register_all(
) {
register_status(iii, config, engine_url);
register_ui_manifest(iii, ui);
tracing::info!("registered console::status, console::ui-manifest");
workspace::register(iii);
tracing::info!(
"registered console::status, console::ui-manifest, console::workspace::{{list,open,close}}"
);
}

#[derive(Debug, Deserialize, JsonSchema)]
Expand Down
Loading
Loading