@ai-ecoverse/slicc-spectrum 1.61.0 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/slicc-dummy.js +13 -0
- package/dist/slicc-dummy.js.map +2 -2
- package/dist/slicc-ui.js +62 -2
- package/dist/slicc-ui.js.map +2 -2
- package/dist/types/app/composer.d.ts +7 -2
- package/dist/types/dummy/agent.d.ts +3 -1
- package/dist/types/dummy/index.d.ts +3 -2
- package/dist/types/model/types.d.ts +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -140,7 +140,7 @@ Text is Adobe Clean Spectrum VF, falling back to Adobe Clean, and code is Spectr
|
|
|
140
140
|
| `<slicc-notices>` | The model's `notices` as in-line alerts with their actions and a close button, after a banner from the `tabs` port when another tab is paused or runs a different SLICC, and a warning for each waiting approval when the `approvals` port has no `decide` (`[data-approval-notice]`); renders nothing without any. |
|
|
141
141
|
| `<slicc-approvals>` | The model's waiting `approvals` as a modal alert dialog, one at a time, oldest first; `<slicc-app>` mounts it. Renders nothing without `approvals.decide`. |
|
|
142
142
|
| `<slicc-follow>` | The model's `follow` state. By default a header chip (`#chip[data-follow]` with the link state: **Connecting to**, **Following**, **Reconnecting to**, **Unlinked from** or **Can’t reach** the owner; `compact` keeps only a follow icon and the light) whose popover says what this device can do (`[data-can]`), that the conversation may be out of date while reconnecting, and with Control that sending waits (`[data-reconnecting]`), and has **Leave** (`data-action="leave"`, behind a confirm unless unlinked). With `page`, the full page for `connecting`, `waiting` (connected without View: "Waiting for {owner} to allow this device"), `unlinked` and `failed` (`[data-follow-page]`), with **Try again** (`data-action="retry"`) when failed and the port has `retry`, and **Leave**. A rejected call shows its message (`[data-error]`). Renders nothing without the port. |
|
|
143
|
-
| `<slicc-composer>` | The message box. <kbd>Enter</kbd> sends, or steers a running reply: the message joins after the current tool round, without interrupting; <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>Enter</kbd> queues a follow-up that runs after the reply and can be withdrawn; <kbd>Shift</kbd>+<kbd>Enter</kbd> adds a line; <kbd>Tab</kbd> takes the suggested follow-up; <kbd>↑</kbd>/<kbd>↓</kbd> at the start or end walk this agent's history; <kbd>Esc</kbd> stops. `/` completes commands (`/clear`, `/compact`, `/model`, `/thinking`, `/scoop`, `/stop`, `/freeze` when the port can freeze, `/theme`) and their arguments, `@` mentions agents and files. Attach from the computer, from SLICC's files, a browser screenshot or a shared secret, or paste and drop files (25 MB each). Queued messages wait above it, to send now or drop. Model and thinking pickers, and dictation where the browser has speech recognition. Drafts are kept per agent. On a follower while the link reconnects, the field is disabled and says so; the draft stays. |
|
|
143
|
+
| `<slicc-composer>` | The message box. <kbd>Enter</kbd> sends, or steers a running reply: the message joins after the current tool round, without interrupting; <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>Enter</kbd> queues a follow-up that runs after the reply and can be withdrawn; <kbd>Shift</kbd>+<kbd>Enter</kbd> adds a line; <kbd>Tab</kbd> takes the suggested follow-up; <kbd>↑</kbd>/<kbd>↓</kbd> at the start or end walk this agent's history; <kbd>Esc</kbd> stops. `/` completes commands (`/clear`, `/compact`, `/model`, `/thinking`, `/scoop`, `/stop`, `/freeze` when the port can freeze, `/theme`) and their arguments, `@` mentions agents and files. Attach from the computer, from SLICC's files, a browser screenshot or a shared secret, or paste and drop files (25 MB each). Queued messages wait above it, to send now or drop. Model and thinking pickers, and dictation where the browser has speech recognition. Drafts are kept per agent. On a follower while the link reconnects, the field is disabled and says so; the draft stays. While the agent holds tool results for the vault (`agent.hold()`), a status line above it says "Waiting for the vault" or "Unlock the vault to continue", with how many results are held, and offers the vault's **Unlock** button when locked and the model has a `vault`; if the browser blocks the vault window, the line says to allow pop-ups. |
|
|
144
144
|
| `<slicc-files>` | The file system as a `<slicc-file-tree>`, with pending changes as git status. Opening a file opens it in a tab. With `files.mountFolder`, **Mount a folder…** (`data-action="mount-folder"`) mounts a local folder, then selects and expands it in the tree; with `files.mounts`, a **Mounted** strip lists the mount points (with `files.mountInfo`, each mount with a `source` reads `/mnt/proj · ref-node/proj`, `data-source` on its `.path`), each with **Eject** (`data-action="eject"`, `data-path` the mount point) when the port has `eject`. With `files.needsFolder`, a **Needs a folder** section lists the mount points waiting for a folder, each with **Insert folder…** (`data-action="insert-folder"`, `data-id` the mount point), which calls `mountFolder(path)`. A failed mount, insert or eject shows its message under the bar. |
|
|
145
145
|
| `<slicc-file-view>` | One file (`path`), highlighted, with its pending change and a link to the diff. |
|
|
146
146
|
| `<slicc-changes>` | Pending changes with their author. Opens the diff, accepts or reverts one change or all of them. Changes with a `repo` show their folder relative to it, and no author when `agentId` is `null`; they group under a header per repository (its path and count), even when there is only one, in the order the port returns them. In a diff panel narrower than 480 px, Accept and Revert (`data-action="accept"`, `data-action="revert"`) show only their icons. Revert and Revert all ask with a destructive confirm that says the uncommitted (or, without a repo, pending) changes can't be undone; a failed revert shows its message under the bar. When the port's `unavailable()` returns a string, the panel shows it instead of the list, with each `backtick` span as inline code in the text's color and, below, each command once with a **Copy** button (`data-command`, `data-action="copy-command"`). |
|
|
@@ -217,7 +217,7 @@ With an `agentId` or a `cone`, the caller reaches the shared surfaces, the chats
|
|
|
217
217
|
|
|
218
218
|
| Port | Later backed by | |
|
|
219
219
|
| :--- | :--- | :--- |
|
|
220
|
-
| `agent` | `@ai-ecoverse/slicc-agent` | Cones and scoops, the active agent, conversations, `send` (with attachments, as a send, a steer or a queued follow-up) and `stop`, the queue, suggestions, answers to questions, permission decisions, compaction, clearing (`clear(agentId)` starts a new conversation: on a cone, a port with `freeze` first puts the old one in the Freezer as its own row, which thaws into a cone of its own; a scoop's is just reset), the model per agent and new scoops. The optional `rewind(agentId, messageId)` drops the user turn before that message and everything after it, and resolves with the turn's prompt (text and attachments) for the composer, or `null`. The optional `drop(agentId)` removes a scoop: it stops and its working folder is deleted, while its conversation and reports are kept, and `createCone(name)` resolves with a new cone; the dummy rejects a cone name that is taken. `freeze(agentId)` is optional too: without it, **Delete cone** and `/freeze` don't show. `frozen()` lists the Freezer's rows; a `FrozenCone` may carry `kind` (`cone`, `scoop` or `agent`), `live` for a conversation that's still running, and `thawedAs`, the id of the cone a scoop or agent run was thawed into. `thaw(id)` brings a cone back, or forks a scoop or agent run into a new cone, and `discard(id)` removes a row. Names don't have to be unique, and an optional `Agent.title` names a cone's conversation; without it, the first user message does. Assistant messages stream: the same message is re-emitted as its parts grow and its tool calls go from `running` to `done`. |
|
|
220
|
+
| `agent` | `@ai-ecoverse/slicc-agent` | Cones and scoops, the active agent, conversations, `send` (with attachments, as a send, a steer or a queued follow-up) and `stop`, the queue, suggestions, answers to questions, permission decisions, compaction, clearing (`clear(agentId)` starts a new conversation: on a cone, a port with `freeze` first puts the old one in the Freezer as its own row, which thaws into a cone of its own; a scoop's is just reset), the model per agent and new scoops. The optional `rewind(agentId, messageId)` drops the user turn before that message and everything after it, and resolves with the turn's prompt (text and attachments) for the composer, or `null`. The optional `hold()` returns an `AgentHold` (`{ reason: waiting | locked, held }`) while tool results wait for the vault (slicc-agent's `connection.vault`: `waiting` while the vault port doesn't answer, `locked` while it needs a passkey), or `null`, with a `hold` event when it changes. The optional `drop(agentId)` removes a scoop: it stops and its working folder is deleted, while its conversation and reports are kept, and `createCone(name)` resolves with a new cone; the dummy rejects a cone name that is taken. `freeze(agentId)` is optional too: without it, **Delete cone** and `/freeze` don't show. `frozen()` lists the Freezer's rows; a `FrozenCone` may carry `kind` (`cone`, `scoop` or `agent`), `live` for a conversation that's still running, and `thawedAs`, the id of the cone a scoop or agent run was thawed into. `thaw(id)` brings a cone back, or forks a scoop or agent run into a new cone, and `discard(id)` removes a row. Names don't have to be unique, and an optional `Agent.title` names a cone's conversation; without it, the first user message does. Assistant messages stream: the same message is re-emitted as its parts grow and its tool calls go from `running` to `done`. |
|
|
221
221
|
| `files` | slicc-kernel's OPFS | `list`, `read`, `write`, `remove`, and pending changes with their before and after text (`accept`, `revert`). The optional `mountFolder()` asks for a local folder and resolves with its mount point (for example `/mnt/photos`), or `null` when the user cancels; the panel calls it synchronously in the click, so the port can call `showDirectoryPicker()`. The optional `mounts()` lists the mount points, and the optional `mountInfo()` returns `MountInfo`s (`target`, optional `source` such as a linked device's `ref-node/proj`, and `type`) for them, used instead of `mounts()` when present; `eject(path)` unmounts one (the folder stays on disk). `mountFolder(path)` inserts the picked folder at a mount point that waits for one; the optional `needsFolder()` lists those mount points. The port emits `mounts` and then `files` after every mount and eject, including those made from the shell, and `mounts` whenever `needsFolder()` changes. |
|
|
222
222
|
| `terminals` | slicc-kernel's terminal API | Terminal sessions; `backend(id)` returns a `TerminalBackend` for `<slicc-terminal>`. |
|
|
223
223
|
| `browser` | `@ai-ecoverse/slicc-cdp` | Tabs, the active tab, `open`, `navigate`, `close`, `screenshot`. A `BrowserTab` may say it's `controlled` (an agent, or the user's terminal when `agentId` is `null`, is driving it now; `agentId` is the agent of its last action); `favicon` is ignored. The optional `actions(tabId?)` returns recent `BrowserAction`s (`{ id, tabId, agentId, kind, target?, value?, length?, status: running \| done \| failed, error?, at }`, `kind` one of `open`, `goto`, `back`, `reload`, `close`, `select`, `snapshot`, `screenshot`, `eval`, `click`, `fill`, `type`, `press`, `scroll`, `request`; a `request` has `value` `'GET https://host/path'` and may have no tab), with an `action` event per new or settled action. The optional `watch(tabId, size?)` streams `frame` events (`{ tabId, src, at }`) for a controlled tab and returns a stop function; the panel watches only the focused tab while it's controlled and visible, with the frame's CSS size. **Stop** calls `agent.stop(agentId)`. |
|
|
@@ -243,7 +243,7 @@ The dummy supports `createDummyModel({ updates: 'boot' | 'starting' | 'current'
|
|
|
243
243
|
|
|
244
244
|
`createDummyModel({ approvals: 'agent' | 'user' | 'many' | 'follower' | 'fail' | 'soon' | 'elsewhere' | 'withdrawn' | 'secrets' })` (`?approvals=` on `/ui/`) adds waiting sudo requests: one from an agent, one from a terminal user, three in a row (the last as `www-data`), one without `decide`, one whose `decide` fails, one that expires in 24 seconds, or two whose first is answered in another tab or withdrawn after a few seconds, or one from an agent that copies a file over `/etc/fnox/config.toml`. Decisions are recorded in `model.approvals.decisions`, and `model.approvals.end(id, reason)` ends a request.
|
|
245
245
|
|
|
246
|
-
`createDummyModel({ vault: 'empty' | 'secrets' | 'notice' | 'locked' | 'off' })` (`?vault=` on `/ui/`, off by default) adds an invented vault: no secrets yet, five secrets (an API key, a jerk lease from pier-nuc revealed to `pier publish`, a Tide Mail sign-in, one without a rule and a removed one) with an activity log that pages back once, the same with a widened rule notice (a new exit and more methods), or locked with a waiting request from docs-pass. Its buttons are plain Spectrum buttons that answer at once: Unlock unlocks, and Replace value and Answer in the vault save the secret. Acknowledged notices are recorded in `model.vault.acknowledged` and created buttons in `model.vault.buttons`. `vaultFixtures`, `DummyVault` and `DummyVaultButton` are exported from `/dummy`.
|
|
246
|
+
`createDummyModel({ vault: 'empty' | 'secrets' | 'notice' | 'locked' | 'off' })` (`?vault=` on `/ui/`, off by default) adds an invented vault: no secrets yet, five secrets (an API key, a jerk lease from pier-nuc revealed to `pier publish`, a Tide Mail sign-in, one without a rule and a removed one) with an activity log that pages back once, the same with a widened rule notice (a new exit and more methods), or locked with a waiting request from docs-pass. Its buttons are plain Spectrum buttons that answer at once: Unlock unlocks, and Replace value and Answer in the vault save the secret. Acknowledged notices are recorded in `model.vault.acknowledged` and created buttons in `model.vault.buttons`. `vaultFixtures`, `DummyVault` and `DummyVaultButton` are exported from `/dummy`. `createDummyModel({ hold: 'waiting' | 'locked' | 'off' })` (`?hold=` on `/ui/`) makes the agent hold two tool results; a `locked` hold clears when the dummy vault unlocks, and `model.agent.setHold(hold)` changes it.
|
|
247
247
|
|
|
248
248
|
On phones the update status and the tray connection show only their status light (the tray's budget is hidden) and the network indicator a cloud icon, with the text in their labels and tooltips; the agent picker keeps room for the cone's name, cut with an ellipsis when long, and the bottom rail scrolls when needed. The update status comes first so progress and failures remain reachable on narrow screens.
|
|
249
249
|
|
package/dist/slicc-dummy.js
CHANGED
|
@@ -604,6 +604,7 @@ var DummyAgent = class extends Emitter {
|
|
|
604
604
|
#messages = /* @__PURE__ */ new Map();
|
|
605
605
|
#queues = /* @__PURE__ */ new Map();
|
|
606
606
|
#frozen = [];
|
|
607
|
+
#hold = null;
|
|
607
608
|
#ice = /* @__PURE__ */ new Map();
|
|
608
609
|
#suggestions = /* @__PURE__ */ new Map();
|
|
609
610
|
#runs = /* @__PURE__ */ new Map();
|
|
@@ -1034,6 +1035,13 @@ var DummyAgent = class extends Emitter {
|
|
|
1034
1035
|
...body ? { body } : {}
|
|
1035
1036
|
});
|
|
1036
1037
|
}
|
|
1038
|
+
hold() {
|
|
1039
|
+
return this.#hold && { ...this.#hold };
|
|
1040
|
+
}
|
|
1041
|
+
setHold(hold) {
|
|
1042
|
+
this.#hold = hold && { ...hold };
|
|
1043
|
+
this.emit("hold", this.hold());
|
|
1044
|
+
}
|
|
1037
1045
|
frozen() {
|
|
1038
1046
|
const live = this.#agents.filter((agent) => !agent.frozen).map((agent) => {
|
|
1039
1047
|
const messages = this.#messages.get(agent.id);
|
|
@@ -5876,6 +5884,7 @@ function createDummyModel({
|
|
|
5876
5884
|
approvals = "off",
|
|
5877
5885
|
follow = "off",
|
|
5878
5886
|
vault = "off",
|
|
5887
|
+
hold = "off",
|
|
5879
5888
|
browser: scenario = "idle",
|
|
5880
5889
|
sprinkles: sprinkles2 = "builtin",
|
|
5881
5890
|
monitor = "dummy"
|
|
@@ -5901,6 +5910,7 @@ function createDummyModel({
|
|
|
5901
5910
|
stop(agentId);
|
|
5902
5911
|
browser.release(agentId);
|
|
5903
5912
|
};
|
|
5913
|
+
if (hold !== "off") agent.setHold({ reason: hold, held: 2 });
|
|
5904
5914
|
if (scenario === "driving") void browser.run(drive);
|
|
5905
5915
|
const base = {
|
|
5906
5916
|
agent,
|
|
@@ -5937,6 +5947,9 @@ function createDummyModel({
|
|
|
5937
5947
|
...follow === "off" ? {} : { follow: new DummyFollow(follow, time) },
|
|
5938
5948
|
...vault === "off" ? {} : { vault: new DummyVault(vault, time) }
|
|
5939
5949
|
};
|
|
5950
|
+
base.vault?.on("status", (status) => {
|
|
5951
|
+
if (!status.locked && agent.hold()?.reason === "locked") agent.setHold(null);
|
|
5952
|
+
});
|
|
5940
5953
|
return {
|
|
5941
5954
|
...base,
|
|
5942
5955
|
monitor: new DummyMonitor(base, monitor === "agent" ? agentSections : void 0)
|