clavarium 0.2.369-next.1 → 0.2.370-next.1

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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "clavarium",
3
- "version": "0.2.369-next.1",
3
+ "version": "0.2.370-next.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "clavarium",
9
- "version": "0.2.369-next.1",
9
+ "version": "0.2.370-next.1",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@xterm/addon-fit": "^0.11.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clavarium",
3
- "version": "0.2.369-next.1",
3
+ "version": "0.2.370-next.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "A conversation is a VM with a terminal in it. Everything else is a folder.",
@@ -559,8 +559,9 @@ export async function handleExternal(request, response, { keys, status, chats =
559
559
  if (typeof text !== 'string' || !text.trim()) throw new Refusal(400, 'Say something: text.');
560
560
  if (text.length > SAY_MAX) throw new Refusal(400, `${SAY_MAX} characters at most.`);
561
561
  if (to !== undefined && to !== null && (!Array.isArray(to) || to.length > 20 || to.some((x) => typeof x !== 'string'))) throw new Refusal(400, 'to: the names of AIs of this room.');
562
- await rooms.say(room, text, { as: keys.roomSignature(id), to: Array.isArray(to) ? to : [] });
563
- return { ok: true };
562
+ const done = await rooms.say(room, text, { as: keys.roomSignature(id), to: Array.isArray(to) ? to : [] });
563
+ /* Posted; an AI it could not reach (its chat off) said by name. */
564
+ return done?.missed?.length ? { ok: true, notReached: done.missed.map((m) => m.name) } : { ok: true };
564
565
  };
565
566
  const boxesListed = (id) => {
566
567
  const there = new Map((boxes?.list() ?? []).map((b) => [b.id, b]));
package/server/rooms.mjs CHANGED
@@ -272,16 +272,25 @@ export class Rooms {
272
272
  const said = now.messages.at(-1);
273
273
  const named = (Array.isArray(to) ? to : []).map((x) => members.find((m) => m.id === x && m.kind === 'ai')).filter(Boolean);
274
274
  const host = members.find((m) => m.id === room.host);
275
+ /* Kept in the room whatever happens next: an AI that cannot be reached (its chat off) is said back by name,
276
+ never as a failure of what was already posted (07-11). */
277
+ const missed = [];
275
278
  for (const ai of named.length ? named : host ? [host] : []) {
276
279
  this.#think(room.id, ai.id, true);
277
- /* Its own copy of each file, in its chat's files: as if attached there (a fresh read of the room's file). */
278
- const copies = [];
279
- for (const f of attached) { const stream = createReadStream(f.file); stream.headers = { 'content-length': String(f.size) }; copies.push((await this.#attach(ai.ref, f.name, stream)).path); }
280
- await this.#say(ai.ref, text, { by: { id: who.id, name: who.name, kind: who.kind, look: who.look }, room: { id: room.id, name: room.name, message: said.id } }, ...(copies.length ? [copies] : []));
280
+ try {
281
+ /* Its own copy of each file, in its chat's files: as if attached there (a fresh read of the room's file). */
282
+ const copies = [];
283
+ for (const f of attached) { const stream = createReadStream(f.file); stream.headers = { 'content-length': String(f.size) }; copies.push((await this.#attach(ai.ref, f.name, stream)).path); }
284
+ await this.#say(ai.ref, text, { by: { id: who.id, name: who.name, kind: who.kind, look: who.look }, room: { id: room.id, name: room.name, message: said.id } }, ...(copies.length ? [copies] : []));
285
+ } catch (error) {
286
+ if (!(error instanceof Refusal)) throw error;
287
+ this.#think(room.id, ai.id, false);
288
+ missed.push({ name: ai.name, why: error.message });
289
+ }
281
290
  }
282
291
  /* Handed to its AIs: read, as a conversation's agent would say it (06-11: the clock stayed on every message). */
283
292
  try { t.seen?.(); } catch { /* an older Parley */ }
284
- return this.read(id);
293
+ return missed.length ? { ...this.read(id), missed } : this.read(id);
285
294
  }
286
295
 
287
296
  /* AN AI ANSWERS IN A ROOM (what its own folder says, entry.room): only to a room it is in; signed by where it
@@ -24,6 +24,8 @@ export const SETTINGS_WORDS_FR = {
24
24
  'set-free-of': '{free} libres sur {total}', 'set-left-of': '{free} restants sur {total}', 'set-highest': 'au plus {n} % en 1 h',
25
25
  'set-core': '1 cœur', 'set-cores': '{n} cœurs',
26
26
  'set-update-out': '{v} est sortie', 'set-up-to-date': 'À jour · {v}', 'set-wifi-on': 'Wi-Fi · {name}', 'set-wifi-off': 'Wi-Fi non utilisé', 'set-cable': 'Câble',
27
+ /* A room message an AI could not get (its chat off): rooms.mjs say, missed. */
28
+ 'set-room-missed': '{names} ne l\'a pas reçu : discussion coupée',
27
29
  /* A box's learning session (boxcollect.mjs): the radio, its false wakes kept. */
28
30
  'set-collect': 'Séance d\'apprentissage (radio)', 'set-collect-from': 'de', 'set-collect-to': 'à',
29
31
  'set-collect-go': 'Programmer', 'set-collect-stop': 'Arrêter', 'set-collect-scheduled': 'Programmée de {from} à {to}',
package/web/app.js CHANGED
@@ -5613,7 +5613,13 @@
5613
5613
  if (known && JSON.stringify(thinkingOf(known)) !== JSON.stringify(who)) { known.thinking = who; paint(); }
5614
5614
  return d;
5615
5615
  }),
5616
- send: (text, answers, files) => post(`${API}/rooms/${id}/talk`, { text, ...(files?.length ? { files: files.map((f) => f.path) } : {}) }),
5616
+ /* Kept in the room even when an AI of it could not get it (its chat off, 07-11): said for a moment, by name. */
5617
+ send: async (text, answers, files) => {
5618
+ const d = await post(`${API}/rooms/${id}/talk`, { text, ...(files?.length ? { files: files.map((f) => f.path) } : {}) });
5619
+ const missed = Array.isArray(d?.missed) ? d.missed.map((m) => String(m?.name ?? '')).filter(Boolean) : [];
5620
+ if (missed.length) flash(uiSaid('set-room-missed', '{names} did not get it: chat off', { names: missed.join(', ') }));
5621
+ return d;
5622
+ },
5617
5623
  /* A file attached in a room (06-11): as in a conversation's chat; kept in the room, a copy to each AI the message goes to. */
5618
5624
  attach: { upload: async (file) => { const x = await fetch(`${API}/rooms/${id}/talk/file?${new URLSearchParams({ name: file.name })}`, { method: 'POST', headers: { 'content-type': 'application/octet-stream' }, body: file }); const j = await x.json().catch(() => ({})); if (!x.ok) throw new Error(j.error || 'The file could not be sent.'); return j; } },
5619
5625
  /* A file an AI of the room showed or cited (ai:<member>:work:a.png): read from its own conversation, in the same viewer as in its chat. */