@ai-ecoverse/slicc-spectrum 1.9.0 → 1.11.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 CHANGED
@@ -134,8 +134,8 @@ Text is Adobe Clean and code Spectrum's Source Code Pro. Source Code Pro (OFL) i
134
134
  | `<slicc-app>` | The shell: header with the agent picker, the View menu and the theme switch, rails, a `<slicc-dock>`, and a status bar. Saves the dock layout per screen class to `storage` (default `localStorage`) under `layoutKey`. |
135
135
  | `<slicc-dock>` | Generic. [dockview-core](https://dockview.dev/) 8 with a theme mapped to Spectrum tokens, in its own shadow root. Panels come from `factories` (`name → (params) => HTMLElement`). `open`, `close`, `has`, `content`, `focusPanel`, `cycleGroup`, `cycleTab`, `toJSON`, `restore`, `clear`, and the full `api`. Tabs have a context menu (close, close others, float, maximize). Events: `layout-change`, `active-panel-change`, `panel-close`. |
136
136
  | `<slicc-agents>` | Cones with their scoops, status, context fill and unread count. Selecting one makes it the active agent. |
137
- | `<slicc-chat>` | One thread's conversation (its `agent`, or the active agent if unset), by day: user messages (with attachments, steered, or delegated from another cone), assistant messages (Markdown with tables, task lists, quotes, code and images; thinking; tool calls, grouped into a collapsible cluster from three in a row; media galleries with images, video and audio; action cards for tools, pull requests and status; plans and checklists; inline diffs; question prompts; delegations; link previews; errors with a fix-it action), standalone tool results, system messages (compaction markers, error cards, notices) and licks, SLICC's events into a cone, on every channel. Permission requests are allowed or denied in place. |
138
- | `<slicc-composer>` | The message box. <kbd>Enter</kbd> sends, or queues behind a running reply; <kbd>Ctrl</kbd>/<kbd>⌘</kbd>+<kbd>Enter</kbd> steers (interrupts); <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`, `/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. |
137
+ | `<slicc-chat>` | One thread's conversation (its `agent`, or the active agent if unset), by day: user messages (with attachments, tagged as steered or follow-up by `delivered`, or delegated from another cone), assistant messages (Markdown with tables, task lists, quotes, code and images; thinking; tool calls, grouped into a collapsible cluster from three in a row; media galleries with images, video and audio; action cards for tools, pull requests and status; plans and checklists; inline diffs; question prompts; delegations; link previews; errors with a fix-it action), standalone tool results, system messages (compaction markers, error cards, notices) and licks, SLICC's events into a cone, on every channel. Permission requests are allowed or denied in place. |
138
+ | `<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`, `/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. |
139
139
  | `<slicc-files>` | The file system as a `<slicc-file-tree>`, with pending changes as git status. Opening a file opens it in a tab. |
140
140
  | `<slicc-file-view>` | One file (`path`), highlighted, with its pending change and a link to the diff. |
141
141
  | `<slicc-changes>` | Pending changes with their author. Opens the diff, accepts or reverts one change or all of them. |
@@ -352,40 +352,64 @@ var DummyAgent = class extends Emitter {
352
352
  );
353
353
  this.emit("messages", agentId);
354
354
  }
355
- async send(agentId, input) {
356
- const agent = this.#agent(agentId);
357
- const message = outgoing(input);
358
- const prompt = message.text.trim();
359
- if (!agent || !prompt && !message.attachments?.length) return;
360
- if (this.busy(agentId) && message.mode !== "steer") {
361
- this.#enqueue(agentId, message);
362
- return;
363
- }
364
- this.stop(agentId);
365
- this.#suggestions.delete(agentId);
366
- const run = { stopped: false };
367
- this.#runs.set(agentId, run);
368
- this.#post(agentId, {
355
+ #user(message, delivered) {
356
+ return {
369
357
  id: this.#id("m"),
370
358
  role: "user",
371
- text: prompt,
359
+ text: message.text.trim(),
372
360
  createdAt: Date.now(),
373
- ...message.mode === "steer" ? { mode: "steer" } : {},
361
+ delivered,
362
+ ...delivered === "steer" ? { mode: "steer" } : {},
374
363
  ...message.attachments?.length ? { attachments: message.attachments } : {}
375
- });
376
- const reply = {
364
+ };
365
+ }
366
+ #reply(model) {
367
+ return {
377
368
  id: this.#id("m"),
378
369
  role: "assistant",
379
370
  parts: [],
380
371
  status: "streaming",
381
372
  createdAt: Date.now(),
382
- model: agent.model
373
+ model
383
374
  };
375
+ }
376
+ async send(agentId, input) {
377
+ const message = outgoing(input);
378
+ if (!this.#agent(agentId) || !message.text.trim() && !message.attachments?.length) return;
379
+ const run = this.#runs.get(agentId);
380
+ if (run && message.mode === "queue") {
381
+ this.#enqueue(agentId, message);
382
+ return;
383
+ }
384
+ if (run) {
385
+ run.steers.push(message);
386
+ return;
387
+ }
388
+ await this.#run(agentId, message, "run");
389
+ }
390
+ async #run(agentId, message, delivered) {
391
+ const agent = this.#agent(agentId);
392
+ const prompt = message.text.trim();
393
+ this.#suggestions.delete(agentId);
394
+ const run = { stopped: false, steers: [] };
395
+ this.#runs.set(agentId, run);
396
+ this.#post(agentId, this.#user(message, delivered));
397
+ let reply = this.#reply(agent.model);
384
398
  this.#post(agentId, reply);
385
- const { steps, suggestion } = script(prompt, message.attachments ?? []);
386
- for (const step of steps) {
387
- if (run.stopped) break;
388
- await this.#step(agentId, reply, step, run);
399
+ let { steps, suggestion } = script(prompt, message.attachments ?? []);
400
+ while (steps.length && !run.stopped) {
401
+ await this.#step(agentId, reply, steps[0], run);
402
+ steps = steps.slice(1);
403
+ if (run.steers.length && !run.stopped && steps.length) {
404
+ reply.status = "done";
405
+ this.emit("message", { agentId, message: reply });
406
+ const steers = run.steers.splice(0);
407
+ for (const steer of steers) this.#post(agentId, this.#user(steer, "steer"));
408
+ const latest = steers.at(-1);
409
+ ({ steps, suggestion } = script(latest.text.trim(), latest.attachments ?? []));
410
+ reply = this.#reply(agent.model);
411
+ this.#post(agentId, reply);
412
+ }
389
413
  }
390
414
  reply.status = run.stopped ? "stopped" : "done";
391
415
  reply.usage = {
@@ -400,6 +424,15 @@ var DummyAgent = class extends Emitter {
400
424
  this.emit("message", { agentId, message: reply });
401
425
  agent.status = "idle";
402
426
  this.#changed();
427
+ const late = run.steers.splice(0);
428
+ if (run.stopped) {
429
+ for (const steer of late) this.#enqueue(agentId, steer);
430
+ } else if (late.length) {
431
+ const last = late.pop();
432
+ for (const steer of late) this.#post(agentId, this.#user(steer, "steer"));
433
+ await this.#run(agentId, last, "steer");
434
+ return;
435
+ }
403
436
  await this.#drain(agentId);
404
437
  }
405
438
  async #drain(agentId) {
@@ -408,7 +441,7 @@ var DummyAgent = class extends Emitter {
408
441
  if (!next) return;
409
442
  this.#queues.set(agentId, rest);
410
443
  this.emit("messages", agentId);
411
- await this.send(agentId, { text: next.text, attachments: next.attachments });
444
+ await this.#run(agentId, { text: next.text, attachments: next.attachments }, "follow-up");
412
445
  }
413
446
  stop(agentId) {
414
447
  const run = this.#runs.get(agentId);
@@ -2505,7 +2538,8 @@ function events() {
2505
2538
  },
2506
2539
  {
2507
2540
  type: "error",
2508
- message: "The model returned 413: the request is larger than its context window.",
2541
+ message: "The request is too large for this model.",
2542
+ detail: "The model returned 413: the request is larger than its context window.",
2509
2543
  action: "change-model"
2510
2544
  }
2511
2545
  ]