From 6bad293b292e1cb95f9903fb4d56f926f1f3a940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Bene=C5=A1?= Date: Mon, 9 Nov 2026 16:55:09 +0000 Subject: [PATCH] Subagents by name; the activity panel as the reference: header button, compact, tasks - "Subagents" everywhere a person reads it (chip, popover with Fewest/Most, scheduled task, panel); offered per the server's `subagents` on a model or chat where it says it, else as before; the fields' most is the server's cap, else 32. No subagent-model setting. - Panel: always reachable from the header's button; the line above the composer only while something runs; Environment for an agent chat; Context with "N until auto-compact" and a Compact button (POST /chats/{chat}/compact; a server without it is said so); Background tasks under Running with elapsed time and a stop square each, unfolding to kind, step, live text and conversation, nested tasks folded under their parent, Finished N folded; Room and Plan as sections. - i18n: 24 new sentences x 8 languages, 9 retired; CHANGELOG [Unreleased]. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 17 +++ scripts/gen-i18n.py | 250 ++++++++++++++++++++++++++++++++----- ui/app.css | 76 +++++++++--- ui/i18n.js | 264 ++++++++++++++++++++++++++++----------- ui/js/activity.js | 294 ++++++++++++++++++++++++++++++++------------ ui/js/chat.js | 50 +++++--- ui/js/dom.js | 1 + ui/js/main.js | 5 +- ui/js/models.js | 44 ++++--- ui/js/scheduled.js | 8 +- 10 files changed, 773 insertions(+), 236 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe21ee0..feccf50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,23 @@ All notable changes to LLeMbas Desktop. The format follows ## [Unreleased] +### Changed + +- **Subagents**, by that name everywhere. The chip under the message box says **Subagents** with the + fewest and the most a chat runs, and opens the two fields under those words; it shows where the + server offers subagents for the chat (for a new chat, for its model), and the most is the + server's cap. Subagents work on the chat's own model unless you name another one in the chat -- + there is no setting for a subagent's model. A scheduled task's field is **Subagents** too. +- **The activity panel, reshaped.** A button in the chat's header opens it at any time, and the + line above the message box shows only while something runs ("3 running · 1 queued · 2 + finished"). An agent chat's **Environment** (its folder, and where it is) comes first. **Context** + says how far it is to the automatic compaction ("80.6k until auto-compact") beside a **Compact** + button that summarises the earlier turns now. **Background tasks** lists subagents, a team's + members and background commands under **Running**, each with how long it has run and a stop + square, unfolding to what it is, its latest step, what it is writing and its conversation; the + tasks under one fold beneath it ("2 tasks"), and the finished ones fold away under **Finished**. + The team's **Room** and the **Plan** have sections of their own. + ## [1.0.0-beta.4] — 2026-11-09 Carries LLeMbas CLI 2.0.0-beta.3 and the look of LLeMbas 2.0.0-beta.6. Scheduled tasks need LLeMbas diff --git a/scripts/gen-i18n.py b/scripts/gen-i18n.py index c59633a..785fd6f 100755 --- a/scripts/gen-i18n.py +++ b/scripts/gen-i18n.py @@ -196,8 +196,6 @@ KEYS = ( "Think before answering", "Fewest", "Most", - "Agents", - "Its own agent included. Above one, it can add members that do the work while it leads them.", "Continue in a terminal…", "Continue in a terminal", "Run this in a terminal: the agent's session goes on there, in this chat's folder, and the chat keeps it.", @@ -207,8 +205,6 @@ KEYS = ( "Back", "Open the activity panel", "Close the activity panel", - "1 agent working", - "%(n)s agents working", "%(n)s queued", "%(n)s waiting", "%(n)s finished", @@ -240,9 +236,7 @@ KEYS = ( "Estimated: no reply has been counted yet.", "%(n)s tools offered.", "No files written in this chat yet.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.", "Nothing running.", - "Team: %(size)s of %(max)s agents", "Show %(n)s more", "Room", "report", @@ -323,8 +317,6 @@ KEYS = ( "A busy model is waited for, then the next free one is used.", "A result, but not a run with nothing to report.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.", - "A team of up to %(n)s", - "A team works on it together, its own agent included.", "Choose a model to choose its effort.", "Due %(when)s", "Each run sees the ones before it.", @@ -333,7 +325,6 @@ KEYS = ( "Edit %(title)s", "Every result, even with nothing to report.", "Models for scheduled tasks", - "No team", "Only in its history.", "Open the chat", "Result", @@ -358,6 +349,31 @@ KEYS = ( "Open its chat", "The model's own", "run by hand", + # activity.js, chat.js, models.js, scheduled.js: subagents, the panel, Compact + "%(n)s running", + "1 task", + "%(n)s tasks", + "%(tokens)s until auto-compact", + "Automatic compaction is off.", + "Compacts before the next reply.", + "Compacts by itself once the window is known.", + "Compact", + "Compacting…", + "Summarise the earlier turns now and send the summary in their place.", + "This server cannot compact a chat from the app yet; the web interface can.", + "Context and background tasks", + "Environment", + "Finished %(n)s", + "Background command", + "Subagent", + "Team member", + "Subagents", + "None", + "Up to %(n)s at once", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.", + "Team: %(size)s of at most %(max)s subagents", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.", + "How many work on it at once, the run's own agent among them, on the same model.", ) # The app's own sentences. The mode names (Manual, Edit, Auto, Plan) stay English, as the @@ -365,6 +381,30 @@ KEYS = ( # the device, as the server's catalogue has it. OWN: dict[str, dict[str, str]] = { "cs": { + "%(n)s running": "Běží: %(n)s", + "1 task": "1 úloha", + "%(n)s tasks": "Úlohy: %(n)s", + "%(tokens)s until auto-compact": "%(tokens)s do automatického shrnutí", + "Automatic compaction is off.": "Automatické shrnutí je vypnuté.", + "Compacts before the next reply.": "Shrne se před další odpovědí.", + "Compacts by itself once the window is known.": "Shrne se samo, jakmile bude známé okno.", + "Compact": "Shrnout", + "Compacting…": "Shrnuje se…", + "Summarise the earlier turns now and send the summary in their place.": "Shrnout dřívější kola hned a posílat místo nich shrnutí.", + "This server cannot compact a chat from the app yet; the web interface can.": "Tento server zatím neumí shrnout konverzaci z aplikace; webové rozhraní to umí.", + "Context and background tasks": "Kontext a úlohy na pozadí", + "Environment": "Prostředí", + "Finished %(n)s": "Dokončeno: %(n)s", + "Background command": "Příkaz na pozadí", + "Subagent": "Subagent", + "Team member": "Člen týmu", + "Subagents": "Subagenti", + "None": "Žádní", + "Up to %(n)s at once": "Nejvýše %(n)s současně", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Na pozadí nic neběží. Subagenti, členové týmu a příkazy na pozadí se tu zobrazí, dokud pracují.", + "Team: %(size)s of at most %(max)s subagents": "Tým: %(size)s z nejvýše %(max)s subagentů", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Nejméně a nejvíce subagentů, které tato konverzace spouští. Pracují na stejném modelu, pokud v konverzaci nepojmenujete jiný.", + "How many work on it at once, the run's own agent among them, on the same model.": "Kolik jich na ní pracuje současně, včetně vlastního agenta běhu, na stejném modelu.", "Menu": "Nabídka", "Minimise": "Minimalizovat", "Maximise": "Maximalizovat", @@ -532,8 +572,6 @@ OWN: dict[str, dict[str, str]] = { "A busy model is waited for, then the next free one is used.": "Na zaneprázdněný model se čeká, pak se použije další volný.", "A result, but not a run with nothing to report.": "Výsledek, ale ne spuštění, které nemá co hlásit.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Úloha bez vlastního modelu běží na prvním volném z těchto, v tomto pořadí. Žádný nezaškrtnutý: všechny.", - "A team of up to %(n)s": "Tým: nejvýše %(n)s", - "A team works on it together, its own agent included.": "Pracuje na ní tým společně, včetně jejího vlastního agenta.", "Choose a model to choose its effort.": "Vyberte model, abyste mohli zvolit jeho náročnost.", "Due %(when)s": "Naplánováno na %(when)s", "Each run sees the ones before it.": "Každé spuštění vidí ta předchozí.", @@ -542,7 +580,6 @@ OWN: dict[str, dict[str, str]] = { "Edit %(title)s": "Upravit %(title)s", "Every result, even with nothing to report.": "Každý výsledek, i když není co hlásit.", "Models for scheduled tasks": "Modely pro naplánované úlohy", - "No team": "Bez týmu", "Only in its history.": "Jen v její historii.", "Open the chat": "Otevřít konverzaci", "Result": "Výsledek", @@ -563,6 +600,30 @@ OWN: dict[str, dict[str, str]] = { "No day ticked: every day.": "Žádný den nezaškrtnutý: každý den.", }, "de": { + "%(n)s running": "%(n)s laufen", + "1 task": "1 Aufgabe", + "%(n)s tasks": "%(n)s Aufgaben", + "%(tokens)s until auto-compact": "%(tokens)s bis zur automatischen Zusammenfassung", + "Automatic compaction is off.": "Die automatische Zusammenfassung ist aus.", + "Compacts before the next reply.": "Wird vor der nächsten Antwort zusammengefasst.", + "Compacts by itself once the window is known.": "Wird von selbst zusammengefasst, sobald das Fenster bekannt ist.", + "Compact": "Zusammenfassen", + "Compacting…": "Wird zusammengefasst…", + "Summarise the earlier turns now and send the summary in their place.": "Die früheren Runden jetzt zusammenfassen und stattdessen die Zusammenfassung senden.", + "This server cannot compact a chat from the app yet; the web interface can.": "Dieser Server kann einen Chat noch nicht aus der App zusammenfassen; die Weboberfläche kann es.", + "Context and background tasks": "Kontext und Hintergrundaufgaben", + "Environment": "Umgebung", + "Finished %(n)s": "Fertig: %(n)s", + "Background command": "Hintergrundbefehl", + "Subagent": "Subagent", + "Team member": "Teammitglied", + "Subagents": "Subagenten", + "None": "Keine", + "Up to %(n)s at once": "Bis zu %(n)s gleichzeitig", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Im Hintergrund läuft nichts. Subagenten, die Mitglieder eines Teams und Hintergrundbefehle erscheinen hier, solange sie arbeiten.", + "Team: %(size)s of at most %(max)s subagents": "Team: %(size)s von höchstens %(max)s Subagenten", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Die wenigsten und die meisten Subagenten, die dieser Chat startet. Sie arbeiten mit demselben Modell, außer Sie nennen im Chat ein anderes.", + "How many work on it at once, the run's own agent among them, on the same model.": "Wie viele gleichzeitig daran arbeiten, der eigene Agent des Laufs mitgezählt, mit demselben Modell.", "Menu": "Menü", "Minimise": "Minimieren", "Maximise": "Maximieren", @@ -730,8 +791,6 @@ OWN: dict[str, dict[str, str]] = { "A busy model is waited for, then the next free one is used.": "Auf ein belegtes Modell wird gewartet, dann wird das nächste freie genommen.", "A result, but not a run with nothing to report.": "Ein Ergebnis, aber kein Lauf ohne Neuigkeiten.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Eine Aufgabe ohne eigenes Modell läuft auf dem ersten freien davon, in dieser Reihenfolge. Keines angehakt: alle.", - "A team of up to %(n)s": "Ein Team mit bis zu %(n)s", - "A team works on it together, its own agent included.": "Ein Team arbeitet gemeinsam daran, ihr eigener Agent eingeschlossen.", "Choose a model to choose its effort.": "Wählen Sie ein Modell, um seinen Aufwand zu wählen.", "Due %(when)s": "Fällig %(when)s", "Each run sees the ones before it.": "Jeder Lauf sieht die vorherigen.", @@ -740,7 +799,6 @@ OWN: dict[str, dict[str, str]] = { "Edit %(title)s": "%(title)s bearbeiten", "Every result, even with nothing to report.": "Jedes Ergebnis, auch ohne Neuigkeiten.", "Models for scheduled tasks": "Modelle für geplante Aufgaben", - "No team": "Kein Team", "Only in its history.": "Nur in ihrem Verlauf.", "Open the chat": "Chat öffnen", "Result": "Ergebnis", @@ -761,6 +819,30 @@ OWN: dict[str, dict[str, str]] = { "No day ticked: every day.": "Kein Tag angehakt: jeden Tag.", }, "es": { + "%(n)s running": "%(n)s en marcha", + "1 task": "1 tarea", + "%(n)s tasks": "%(n)s tareas", + "%(tokens)s until auto-compact": "%(tokens)s hasta la compactación automática", + "Automatic compaction is off.": "La compactación automática está desactivada.", + "Compacts before the next reply.": "Se compacta antes de la próxima respuesta.", + "Compacts by itself once the window is known.": "Se compacta sola en cuanto se conozca la ventana.", + "Compact": "Compactar", + "Compacting…": "Compactando…", + "Summarise the earlier turns now and send the summary in their place.": "Resumir ahora los turnos anteriores y enviar el resumen en su lugar.", + "This server cannot compact a chat from the app yet; the web interface can.": "Este servidor aún no puede compactar un chat desde la aplicación; la interfaz web sí puede.", + "Context and background tasks": "Contexto y tareas en segundo plano", + "Environment": "Entorno", + "Finished %(n)s": "Terminadas: %(n)s", + "Background command": "Comando en segundo plano", + "Subagent": "Subagente", + "Team member": "Miembro del equipo", + "Subagents": "Subagentes", + "None": "Ninguno", + "Up to %(n)s at once": "Hasta %(n)s a la vez", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "No hay nada en segundo plano. Los subagentes, los miembros de un equipo y los comandos en segundo plano aparecen aquí mientras trabajan.", + "Team: %(size)s of at most %(max)s subagents": "Equipo: %(size)s de un máximo de %(max)s subagentes", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "El mínimo y el máximo de subagentes que inicia este chat. Usan el mismo modelo, salvo que nombre otro en el chat.", + "How many work on it at once, the run's own agent among them, on the same model.": "Cuántos trabajan en ella a la vez, contando el propio agente de la ejecución, con el mismo modelo.", "Menu": "Menú", "Minimise": "Minimizar", "Maximise": "Maximizar", @@ -928,8 +1010,6 @@ OWN: dict[str, dict[str, str]] = { "A busy model is waited for, then the next free one is used.": "Se espera a un modelo ocupado y luego se usa el siguiente libre.", "A result, but not a run with nothing to report.": "Un resultado, pero no una ejecución sin nada que informar.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Una tarea sin modelo propio se ejecuta en el primero libre de estos, en este orden. Ninguno marcado: todos.", - "A team of up to %(n)s": "Un equipo de hasta %(n)s", - "A team works on it together, its own agent included.": "Un equipo trabaja en ella, incluido su propio agente.", "Choose a model to choose its effort.": "Elija un modelo para elegir su esfuerzo.", "Due %(when)s": "Prevista %(when)s", "Each run sees the ones before it.": "Cada ejecución ve las anteriores.", @@ -938,7 +1018,6 @@ OWN: dict[str, dict[str, str]] = { "Edit %(title)s": "Editar %(title)s", "Every result, even with nothing to report.": "Cada resultado, incluso sin nada que informar.", "Models for scheduled tasks": "Modelos para tareas programadas", - "No team": "Sin equipo", "Only in its history.": "Solo en su historial.", "Open the chat": "Abrir el chat", "Result": "Resultado", @@ -959,6 +1038,30 @@ OWN: dict[str, dict[str, str]] = { "No day ticked: every day.": "Ningún día marcado: todos los días.", }, "fr": { + "%(n)s running": "%(n)s en cours", + "1 task": "1 tâche", + "%(n)s tasks": "%(n)s tâches", + "%(tokens)s until auto-compact": "%(tokens)s avant le compactage automatique", + "Automatic compaction is off.": "Le compactage automatique est désactivé.", + "Compacts before the next reply.": "Compacté avant la prochaine réponse.", + "Compacts by itself once the window is known.": "Compacté de lui-même dès que la fenêtre est connue.", + "Compact": "Compacter", + "Compacting…": "Compactage…", + "Summarise the earlier turns now and send the summary in their place.": "Résumer maintenant les tours précédents et envoyer le résumé à leur place.", + "This server cannot compact a chat from the app yet; the web interface can.": "Ce serveur ne peut pas encore compacter une conversation depuis l’application ; l’interface web le peut.", + "Context and background tasks": "Contexte et tâches en arrière-plan", + "Environment": "Environnement", + "Finished %(n)s": "Terminées : %(n)s", + "Background command": "Commande en arrière-plan", + "Subagent": "Sous-agent", + "Team member": "Membre de l’équipe", + "Subagents": "Sous-agents", + "None": "Aucun", + "Up to %(n)s at once": "Jusqu’à %(n)s à la fois", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Rien ne tourne en arrière-plan. Les sous-agents, les membres d’une équipe et les commandes en arrière-plan s’affichent ici pendant qu’ils travaillent.", + "Team: %(size)s of at most %(max)s subagents": "Équipe : %(size)s sur %(max)s sous-agents au plus", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Le moins et le plus de sous-agents que lance cette conversation. Ils utilisent le même modèle, sauf si vous en nommez un autre dans la conversation.", + "How many work on it at once, the run's own agent among them, on the same model.": "Combien y travaillent à la fois, l’agent de l’exécution compris, avec le même modèle.", "Menu": "Menu", "Minimise": "Réduire", "Maximise": "Agrandir", @@ -1126,8 +1229,6 @@ OWN: dict[str, dict[str, str]] = { "A busy model is waited for, then the next free one is used.": "Un modèle occupé est attendu, puis le suivant libre est utilisé.", "A result, but not a run with nothing to report.": "Un résultat, mais pas une exécution sans rien à signaler.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Une tâche sans modèle à elle tourne sur le premier libre de ceux-ci, dans cet ordre. Aucun coché : tous.", - "A team of up to %(n)s": "Une équipe jusqu'à %(n)s", - "A team works on it together, its own agent included.": "Une équipe y travaille ensemble, son propre agent compris.", "Choose a model to choose its effort.": "Choisissez un modèle pour choisir son effort.", "Due %(when)s": "Prévue %(when)s", "Each run sees the ones before it.": "Chaque exécution voit les précédentes.", @@ -1136,7 +1237,6 @@ OWN: dict[str, dict[str, str]] = { "Edit %(title)s": "Modifier %(title)s", "Every result, even with nothing to report.": "Chaque résultat, même sans rien à signaler.", "Models for scheduled tasks": "Modèles pour les tâches planifiées", - "No team": "Pas d'équipe", "Only in its history.": "Seulement dans son historique.", "Open the chat": "Ouvrir la conversation", "Result": "Résultat", @@ -1157,6 +1257,30 @@ OWN: dict[str, dict[str, str]] = { "No day ticked: every day.": "Aucun jour coché : tous les jours.", }, "hu": { + "%(n)s running": "%(n)s fut", + "1 task": "1 feladat", + "%(n)s tasks": "%(n)s feladat", + "%(tokens)s until auto-compact": "%(tokens)s az automatikus tömörítésig", + "Automatic compaction is off.": "Az automatikus tömörítés ki van kapcsolva.", + "Compacts before the next reply.": "A következő válasz előtt tömörül.", + "Compacts by itself once the window is known.": "Magától tömörül, amint ismert az ablak.", + "Compact": "Tömörítés", + "Compacting…": "Tömörítés…", + "Summarise the earlier turns now and send the summary in their place.": "A korábbi köröket most összefoglalja, és helyettük az összefoglalót küldi.", + "This server cannot compact a chat from the app yet; the web interface can.": "Ez a szerver még nem tud beszélgetést tömöríteni az alkalmazásból; a webes felület tud.", + "Context and background tasks": "Kontextus és háttérfeladatok", + "Environment": "Környezet", + "Finished %(n)s": "Kész: %(n)s", + "Background command": "Háttérparancs", + "Subagent": "Alügynök", + "Team member": "Csapattag", + "Subagents": "Alügynökök", + "None": "Nincs", + "Up to %(n)s at once": "Legfeljebb %(n)s egyszerre", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "A háttérben semmi sem fut. Az alügynökök, egy csapat tagjai és a háttérparancsok itt jelennek meg, amíg dolgoznak.", + "Team: %(size)s of at most %(max)s subagents": "Csapat: %(size)s a legfeljebb %(max)s alügynökből", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "A beszélgetés által indított alügynökök legkisebb és legnagyobb száma. Ugyanazon a modellen dolgoznak, hacsak nem nevez meg másikat a beszélgetésben.", + "How many work on it at once, the run's own agent among them, on the same model.": "Hányan dolgoznak rajta egyszerre, a futás saját ügynökét is beleértve, ugyanazon a modellen.", "Menu": "Menü", "Minimise": "Kis méret", "Maximise": "Teljes méret", @@ -1324,8 +1448,6 @@ OWN: dict[str, dict[str, str]] = { "A busy model is waited for, then the next free one is used.": "A foglalt modellre vár, majd a következő szabadot használja.", "A result, but not a run with nothing to report.": "Eredmény, de nem olyan futás, amelynek nincs mit jelentenie.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "A saját modell nélküli feladat ezek közül az első szabadon fut, ebben a sorrendben. Ha egy sincs bejelölve: mindegyiken.", - "A team of up to %(n)s": "Legfeljebb %(n)s fős csapat", - "A team works on it together, its own agent included.": "Egy csapat dolgozik rajta együtt, a saját ügynökét is beleértve.", "Choose a model to choose its effort.": "Válasszon modellt az erőfeszítés megadásához.", "Due %(when)s": "Esedékes: %(when)s", "Each run sees the ones before it.": "Minden futás látja az előzőeket.", @@ -1334,7 +1456,6 @@ OWN: dict[str, dict[str, str]] = { "Edit %(title)s": "%(title)s szerkesztése", "Every result, even with nothing to report.": "Minden eredmény, akkor is, ha nincs mit jelenteni.", "Models for scheduled tasks": "Modellek az ütemezett feladatokhoz", - "No team": "Nincs csapat", "Only in its history.": "Csak az előzményeiben.", "Open the chat": "A csevegés megnyitása", "Result": "Eredmény", @@ -1355,6 +1476,30 @@ OWN: dict[str, dict[str, str]] = { "No day ticked: every day.": "Ha egy nap sincs bejelölve: minden nap.", }, "it": { + "%(n)s running": "%(n)s in corso", + "1 task": "1 attività", + "%(n)s tasks": "%(n)s attività", + "%(tokens)s until auto-compact": "%(tokens)s alla compattazione automatica", + "Automatic compaction is off.": "La compattazione automatica è disattivata.", + "Compacts before the next reply.": "Si compatta prima della prossima risposta.", + "Compacts by itself once the window is known.": "Si compatta da sola appena la finestra è nota.", + "Compact": "Compatta", + "Compacting…": "Compattazione…", + "Summarise the earlier turns now and send the summary in their place.": "Riassumi ora i turni precedenti e invia il riassunto al loro posto.", + "This server cannot compact a chat from the app yet; the web interface can.": "Questo server non può ancora compattare una chat dall’app; l’interfaccia web sì.", + "Context and background tasks": "Contesto e attività in background", + "Environment": "Ambiente", + "Finished %(n)s": "Terminate: %(n)s", + "Background command": "Comando in background", + "Subagent": "Subagente", + "Team member": "Membro della squadra", + "Subagents": "Subagenti", + "None": "Nessuno", + "Up to %(n)s at once": "Fino a %(n)s alla volta", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Nulla è in esecuzione in background. Subagenti, membri di una squadra e comandi in background compaiono qui mentre lavorano.", + "Team: %(size)s of at most %(max)s subagents": "Squadra: %(size)s su un massimo di %(max)s subagenti", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Il minimo e il massimo di subagenti che questa chat avvia. Lavorano sullo stesso modello, a meno che tu ne nomini un altro nella chat.", + "How many work on it at once, the run's own agent among them, on the same model.": "Quanti ci lavorano alla volta, compreso l’agente dell’esecuzione, sullo stesso modello.", "Menu": "Menu", "Minimise": "Riduci a icona", "Maximise": "Ingrandisci", @@ -1522,8 +1667,6 @@ OWN: dict[str, dict[str, str]] = { "A busy model is waited for, then the next free one is used.": "Si attende un modello occupato, poi si usa il successivo libero.", "A result, but not a run with nothing to report.": "Un risultato, ma non un’esecuzione senza nulla da segnalare.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Un’attività senza un modello proprio gira sul primo libero di questi, in quest’ordine. Nessuno spuntato: tutti.", - "A team of up to %(n)s": "Un team fino a %(n)s", - "A team works on it together, its own agent included.": "Un team ci lavora insieme, incluso il suo agente.", "Choose a model to choose its effort.": "Scegli un modello per sceglierne l’impegno.", "Due %(when)s": "Prevista %(when)s", "Each run sees the ones before it.": "Ogni esecuzione vede quelle precedenti.", @@ -1532,7 +1675,6 @@ OWN: dict[str, dict[str, str]] = { "Edit %(title)s": "Modifica %(title)s", "Every result, even with nothing to report.": "Ogni risultato, anche senza nulla da segnalare.", "Models for scheduled tasks": "Modelli per le attività pianificate", - "No team": "Nessun team", "Only in its history.": "Solo nella sua cronologia.", "Open the chat": "Apri la chat", "Result": "Risultato", @@ -1553,6 +1695,30 @@ OWN: dict[str, dict[str, str]] = { "No day ticked: every day.": "Nessun giorno spuntato: ogni giorno.", }, "pl": { + "%(n)s running": "Działa: %(n)s", + "1 task": "1 zadanie", + "%(n)s tasks": "Zadania: %(n)s", + "%(tokens)s until auto-compact": "%(tokens)s do automatycznego streszczenia", + "Automatic compaction is off.": "Automatyczne streszczanie jest wyłączone.", + "Compacts before the next reply.": "Zostanie streszczona przed następną odpowiedzią.", + "Compacts by itself once the window is known.": "Zostanie streszczona sama, gdy okno będzie znane.", + "Compact": "Streść", + "Compacting…": "Streszczanie…", + "Summarise the earlier turns now and send the summary in their place.": "Streścić teraz wcześniejsze tury i wysyłać streszczenie zamiast nich.", + "This server cannot compact a chat from the app yet; the web interface can.": "Ten serwer nie umie jeszcze streścić czatu z aplikacji; interfejs WWW umie.", + "Context and background tasks": "Kontekst i zadania w tle", + "Environment": "Środowisko", + "Finished %(n)s": "Zakończone: %(n)s", + "Background command": "Polecenie w tle", + "Subagent": "Subagent", + "Team member": "Członek zespołu", + "Subagents": "Subagenci", + "None": "Brak", + "Up to %(n)s at once": "Do %(n)s naraz", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "W tle nic nie działa. Subagenci, członkowie zespołu i polecenia w tle pojawiają się tu, gdy pracują.", + "Team: %(size)s of at most %(max)s subagents": "Zespół: %(size)s z najwyżej %(max)s subagentów", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Najmniej i najwięcej subagentów, których uruchamia ten czat. Pracują na tym samym modelu, chyba że w czacie wskażesz inny.", + "How many work on it at once, the run's own agent among them, on the same model.": "Ilu pracuje nad nim naraz, łącznie z własnym agentem uruchomienia, na tym samym modelu.", "Menu": "Menu", "Minimise": "Minimalizuj", "Maximise": "Maksymalizuj", @@ -1720,8 +1886,6 @@ OWN: dict[str, dict[str, str]] = { "A busy model is waited for, then the next free one is used.": "Na zajęty model się czeka, potem używany jest następny wolny.", "A result, but not a run with nothing to report.": "Wynik, ale nie uruchomienie bez niczego do zgłoszenia.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Zadanie bez własnego modelu działa na pierwszym wolnym z tych, w tej kolejności. Żaden niezaznaczony: wszystkie.", - "A team of up to %(n)s": "Zespół do %(n)s", - "A team works on it together, its own agent included.": "Pracuje nad nim zespół, wraz z jego własnym agentem.", "Choose a model to choose its effort.": "Wybierz model, aby wybrać jego wysiłek.", "Due %(when)s": "Zaplanowane na %(when)s", "Each run sees the ones before it.": "Każde uruchomienie widzi poprzednie.", @@ -1730,7 +1894,6 @@ OWN: dict[str, dict[str, str]] = { "Edit %(title)s": "Edytuj %(title)s", "Every result, even with nothing to report.": "Każdy wynik, nawet bez niczego do zgłoszenia.", "Models for scheduled tasks": "Modele dla zaplanowanych zadań", - "No team": "Bez zespołu", "Only in its history.": "Tylko w jego historii.", "Open the chat": "Otwórz czat", "Result": "Wynik", @@ -1751,6 +1914,30 @@ OWN: dict[str, dict[str, str]] = { "No day ticked: every day.": "Żaden dzień niezaznaczony: codziennie.", }, "sk": { + "%(n)s running": "Beží: %(n)s", + "1 task": "1 úloha", + "%(n)s tasks": "Úlohy: %(n)s", + "%(tokens)s until auto-compact": "%(tokens)s do automatického zhrnutia", + "Automatic compaction is off.": "Automatické zhrnutie je vypnuté.", + "Compacts before the next reply.": "Zhrnie sa pred ďalšou odpoveďou.", + "Compacts by itself once the window is known.": "Zhrnie sa samo, keď bude okno známe.", + "Compact": "Zhrnúť", + "Compacting…": "Zhŕňa sa…", + "Summarise the earlier turns now and send the summary in their place.": "Zhrnúť skoršie kolá hneď a posielať namiesto nich zhrnutie.", + "This server cannot compact a chat from the app yet; the web interface can.": "Tento server zatiaľ nevie zhrnúť konverzáciu z aplikácie; webové rozhranie to vie.", + "Context and background tasks": "Kontext a úlohy na pozadí", + "Environment": "Prostredie", + "Finished %(n)s": "Dokončené: %(n)s", + "Background command": "Príkaz na pozadí", + "Subagent": "Subagent", + "Team member": "Člen tímu", + "Subagents": "Subagenti", + "None": "Žiadni", + "Up to %(n)s at once": "Najviac %(n)s naraz", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Na pozadí nič nebeží. Subagenti, členovia tímu a príkazy na pozadí sa tu zobrazia, kým pracujú.", + "Team: %(size)s of at most %(max)s subagents": "Tím: %(size)s z najviac %(max)s subagentov", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Najmenej a najviac subagentov, ktoré táto konverzácia spúšťa. Pracujú na rovnakom modeli, ak v konverzácii nepomenujete iný.", + "How many work on it at once, the run's own agent among them, on the same model.": "Koľko na nej pracuje naraz, vrátane vlastného agenta behu, na rovnakom modeli.", "Menu": "Ponuka", "Minimise": "Minimalizovať", "Maximise": "Maximalizovať", @@ -1918,8 +2105,6 @@ OWN: dict[str, dict[str, str]] = { "A busy model is waited for, then the next free one is used.": "Na zaneprázdnený model sa čaká, potom sa použije ďalší voľný.", "A result, but not a run with nothing to report.": "Výsledok, ale nie spustenie, ktoré nemá čo hlásiť.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Úloha bez vlastného modelu beží na prvom voľnom z týchto, v tomto poradí. Žiadny nezaškrtnutý: všetky.", - "A team of up to %(n)s": "Tím: najviac %(n)s", - "A team works on it together, its own agent included.": "Pracuje na nej tím spoločne, vrátane jej vlastného agenta.", "Choose a model to choose its effort.": "Vyberte model, aby ste mohli zvoliť jeho náročnosť.", "Due %(when)s": "Naplánované na %(when)s", "Each run sees the ones before it.": "Každé spustenie vidí tie predchádzajúce.", @@ -1928,7 +2113,6 @@ OWN: dict[str, dict[str, str]] = { "Edit %(title)s": "Upraviť %(title)s", "Every result, even with nothing to report.": "Každý výsledok, aj keď nie je čo hlásiť.", "Models for scheduled tasks": "Modely pre naplánované úlohy", - "No team": "Bez tímu", "Only in its history.": "Len v jej histórii.", "Open the chat": "Otvoriť konverzáciu", "Result": "Výsledok", diff --git a/ui/app.css b/ui/app.css index 3b48ecf..ece97e6 100644 --- a/ui/app.css +++ b/ui/app.css @@ -708,17 +708,19 @@ details[open] > summary .step__chev .icon { transform: rotate(90deg); } } .toggle input:checked { background: var(--accent); border-color: var(--accent); } .toggle input:checked::after { background: var(--accent-ink); transform: translateX(var(--check-size)); } -/* The team's size: two number fields of one width with a dash between them, and in the header +/* The subagents, fewest and most: two number fields of one width with a dash between them, and in the header its word before them -- fixed tracks, so nothing moves when a number grows a digit. */ -.agents { +.agents, .agents__heads { display: inline-grid; - grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); + grid-template-columns: minmax(0, 1fr) var(--sp-3) minmax(0, 1fr); gap: var(--sp-2); align-items: center; width: 100%; height: var(--control-h); } -.agents__dash { color: var(--ink-muted); } +.agents__dash { color: var(--ink-muted); text-align: center; } +/* The words over the subagents' two fields, on the fields' own tracks. */ +.agents__heads { height: auto; font-size: var(--text-xs); color: var(--ink-muted); } .agents__input { width: 100%; min-width: 0; height: var(--control-h); padding: 0 var(--control-px-sm); } .agents--compact { grid-template-columns: auto calc(var(--w-field-xs) / 2) auto calc(var(--w-field-xs) / 2); @@ -920,6 +922,14 @@ details[open] > summary .step__chev .icon { transform: rotate(90deg); } .ctx__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--ink-muted); } .ctx__num { font: var(--text-xs) var(--font-mono); text-align: right; color: var(--ink-muted); } .ctx__note { margin: 0; font-size: var(--text-xs); color: var(--ink-faint); } +/* "41k until auto-compact" and the Compact button: the words give, the button keeps its size. */ +.ctx__compact { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-1) var(--sp-2); align-items: center; padding-top: var(--sp-2); border-top: var(--border-w) solid var(--border); } +.ctx__until { color: var(--ink-muted); } +.ctx__error { grid-column: 1 / -1; margin: 0; font-size: var(--text-xs); color: var(--warning); } +/* Environment: an agent chat's folder and where it is. */ +.env { display: grid; grid-template-columns: var(--sp-4) minmax(0, auto) auto; justify-content: start; gap: var(--sp-2); align-items: center; margin: 0; } +.env__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--ink); } +.env__where { font: var(--text-xs) var(--font-mono); color: var(--ink-muted); } .ctx--messages { --ctx: var(--accent); } .ctx--system { --ctx: var(--ink-muted); } .ctx--memory { --ctx: var(--warning); } @@ -943,15 +953,41 @@ details[open] > summary .step__chev .icon { transform: rotate(90deg); } track that gives, cut), elapsed time in a column of its own width, the stop button at its size (an empty box where there is none) -- so rows line up whatever each says. */ .tasks { display: grid; gap: var(--sp-2); min-width: 0; } -.tasks__summary, .tasks__team { margin: 0; color: var(--ink-muted); } +.tasks__team { margin: 0; color: var(--ink-muted); } .tasks__goal { margin: 0; color: var(--ink); } -.tasks__list { display: grid; gap: var(--sp-1); } -.tasks__more > summary { cursor: pointer; padding: var(--sp-1) 0; color: var(--ink-muted); } -.tasks__more[open] > summary { margin-bottom: var(--sp-1); } +.tasks__group { display: grid; grid-template-columns: auto auto; justify-content: start; gap: var(--sp-2); align-items: baseline; margin: var(--sp-1) 0 0; color: var(--ink-muted); } +.tasks__list { display: grid; gap: var(--sp-2); } +/* A fold ("Show 3 more", "Finished 12", a task's own "2 tasks"): a chevron that turns, then the + words; nested ones step in by the depth of what is under them. */ +.tasks__more { margin-left: calc(var(--depth, 0) * var(--sp-4)); min-width: 0; } +.tasks__more > summary { + display: grid; + grid-template-columns: 12px minmax(0, 1fr); + gap: var(--sp-2); + align-items: center; + min-height: var(--row-h); + padding: 0 var(--sp-3); + color: var(--ink-muted); + cursor: pointer; + list-style: none; +} +.tasks__more > summary::-webkit-details-marker { display: none; } +.tasks__more > summary:hover { color: var(--ink); } +.tasks__more[open] > summary { margin-bottom: var(--sp-2); } +.tasks__nested { margin-top: calc(-1 * var(--sp-1)); } +.tasks__finished { padding-top: var(--sp-1); border-top: var(--border-w) solid var(--border); } +.tasks__chev, .agent__chev { display: grid; place-items: center; width: 12px; height: 12px; color: var(--ink-faint); transition: transform var(--dur-1) var(--ease-out); } +.tasks__chev .icon, .agent__chev .icon { width: 12px; height: 12px; } +.tasks__more[open] > summary .tasks__chev, .agent[open] > .agent__row .agent__chev { transform: rotate(90deg); } +@media (prefers-reduced-motion: reduce) { .tasks__chev, .agent__chev { transition: none; } } + +/* A task: one card, one row of known tracks -- the chevron, what it does (the one track that + gives, cut), the elapsed time in a column of its own width, the stop square at its size (an + empty box where it cannot be stopped) -- so the rows line up whatever each says. */ .agent { margin-left: calc(var(--depth, 0) * var(--sp-4)); background: var(--surface); border: var(--border-w) solid var(--border); border-radius: var(--radius-lg); min-width: 0; } .agent__row { display: grid; - grid-template-columns: var(--dot-size) minmax(0, 1fr) var(--time-col) var(--control-h-sm); + grid-template-columns: 12px minmax(0, 1fr) var(--time-col) var(--control-h-sm); gap: var(--sp-2); align-items: center; min-height: var(--control-h); @@ -960,17 +996,21 @@ details[open] > summary .step__chev .icon { transform: rotate(90deg); } list-style: none; } .agent__row::-webkit-details-marker { display: none; } -.agent__dot { width: var(--dot-size); height: var(--dot-size); border-radius: var(--radius-full); background: var(--ink-faint); } -.agent.is-working .agent__dot { background: var(--accent); } -.agent.is-queued .agent__dot, .agent.is-waiting .agent__dot { background: var(--warning); } -.agent.is-done .agent__dot { background: var(--leaf); } -.agent.is-error .agent__dot { background: var(--danger); } +.agent__row:hover { background: var(--surface-hover); border-radius: var(--radius-lg); } .agent__what { display: grid; min-width: 0; } -.agent__name, .agent__role { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } -.agent__name { color: var(--ink); } -.agent__role { font-size: var(--text-xs); color: var(--ink-muted); } +.agent__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--ink); } +.agent.is-done .agent__name, .agent.is-stopped .agent__name { color: var(--ink-muted); } +.agent.is-error .agent__name { color: var(--danger); } +.agent__role { margin: 0; color: var(--ink-muted); overflow-wrap: anywhere; } .agent__time { font: var(--text-xs) var(--font-mono); text-align: right; color: var(--ink-muted); } -.agent__stop { width: var(--control-h-sm); height: var(--control-h-sm); } +.agent.is-queued .agent__time, .agent.is-waiting .agent__time { color: var(--warning); } +/* The stop square: a small filled square in a button the size of the others. */ +.agent__stop { display: grid; place-items: center; width: var(--control-h-sm); height: var(--control-h-sm); padding: 0; background: var(--surface-active); border: 0; border-radius: var(--radius-md); cursor: pointer; } +.agent__stop:hover { background: var(--surface-hover); } +.agent__stop.is-none { background: none; cursor: default; } +.agent__square { width: var(--sp-3); height: var(--sp-3); background: var(--ink); border-radius: var(--radius-sm); } +.agent__stop:hover .agent__square { background: var(--danger); } +.agent__id { font: var(--text-xs) var(--font-mono); color: var(--ink-faint); overflow-wrap: anywhere; } .agent__body { display: grid; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3) var(--sp-3); border-top: var(--border-w) solid var(--border); min-width: 0; } .agent__body > .btn { justify-self: start; } .agent__facts { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); margin: 0; font-size: var(--text-xs); color: var(--ink-muted); } diff --git a/ui/i18n.js b/ui/i18n.js index 56ed091..bc96e71 100644 --- a/ui/i18n.js +++ b/ui/i18n.js @@ -12,10 +12,11 @@ const LEMBAS_I18N = { "cs": { "%(model)s was busy, so it ran on this one.": "%(model)s byl zaneprázdněný, proto běžela na tomto.", - "%(n)s agents working": "Pracující agenti: %(n)s", "%(n)s finished": "Dokončeno: %(n)s", "%(n)s missed": "zmeškáno: %(n)s", "%(n)s queued": "Ve frontě: %(n)s", + "%(n)s running": "Běží: %(n)s", + "%(n)s tasks": "Úlohy: %(n)s", "%(n)s tokens": "tokeny: %(n)s", "%(n)s tools offered.": "Nabízené nástroje: %(n)s.", "%(n)s waiting": "Čeká: %(n)s", @@ -24,7 +25,8 @@ const LEMBAS_I18N = { "%(percent)s%% used": "Využito: %(percent)s %%", "%(steps)s steps, %(tools)s tools": "Kroky: %(steps)s, nástroje: %(tools)s", "%(tokens)s tokens": "%(tokens)s tokenů", - "1 agent working": "1 agent pracuje", + "%(tokens)s until auto-compact": "%(tokens)s do automatického shrnutí", + "1 task": "1 úloha", "A LLeMbas CLI service already runs here (pid %(pid)s), but is not connected: %(why)s": "Služba LLeMbas CLI už tu běží (pid %(pid)s), ale není připojená: %(why)s", "A LLeMbas CLI service already runs here (pid %(pid)s); it is this computer's agent.": "Služba LLeMbas CLI už tu běží (pid %(pid)s); je agentem tohoto počítače.", "A busy model is waited for, then the next free one is used.": "Na zaneprázdněný model se čeká, pak se použije další volný.", @@ -37,8 +39,6 @@ const LEMBAS_I18N = { "A scheduled task has a result.": "Naplánovaná úloha má výsledek.", "A shell as you, in one of these folders.": "Shell pod vaším účtem, v jedné z těchto složek.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Úloha bez vlastního modelu běží na prvním volném z těchto, v tomto pořadí. Žádný nezaškrtnutý: všechny.", - "A team of up to %(n)s": "Tým: nejvýše %(n)s", - "A team works on it together, its own agent included.": "Pracuje na ní tým společně, včetně jejího vlastního agenta.", "About": "O aplikaci", "Account": "Účet", "Activity": "Aktivita", @@ -47,7 +47,6 @@ const LEMBAS_I18N = { "Agent": "Agent", "Agent chats can work in these folders and anything inside them — nowhere else on this computer.": "Agentní konverzace mohou pracovat v těchto složkách a ve všem uvnitř nich — nikde jinde na tomto počítači.", "Agent: %(why)s": "Agent: %(why)s", - "Agents": "Agenti", "Allow": "Povolit", "Always": "Vždy", "Always allow": "Vždy povolit", @@ -58,7 +57,9 @@ const LEMBAS_I18N = { "Archive chat": "Archivovat konverzaci", "Attach files": "Přikládat soubory", "Auto — asks nothing": "Auto — na nic se neptá", + "Automatic compaction is off.": "Automatické shrnutí je vypnuté.", "Back": "Zpět", + "Background command": "Příkaz na pozadí", "Background tasks": "Úlohy na pozadí", "Cancel": "Zrušit", "Carry it out": "Provést to", @@ -71,9 +72,14 @@ const LEMBAS_I18N = { "Close the activity panel": "Zavřít panel aktivity", "Command": "Příkaz", "Commands": "Příkazy", + "Compact": "Shrnout", + "Compacting…": "Shrnuje se…", "Compaction buffer": "Rezerva na zhuštění", + "Compacts before the next reply.": "Shrne se před další odpovědí.", + "Compacts by itself once the window is known.": "Shrne se samo, jakmile bude známé okno.", "Connect": "Připojit", "Context": "Kontext", + "Context and background tasks": "Kontext a úlohy na pozadí", "Continue in a terminal": "Pokračovat v terminálu", "Continue in a terminal…": "Pokračovat v terminálu…", "Copied": "Zkopírováno", @@ -99,22 +105,24 @@ const LEMBAS_I18N = { "Edit message": "Upravit zprávu", "Edit — asks before commands": "Edit — ptá se před příkazy", "Empty folder": "Prázdná složka", + "Environment": "Prostředí", "Estimated: no reply has been counted yet.": "Odhad: žádná odpověď ještě nebyla spočítána.", "Every result, even with nothing to report.": "Každý výsledek, i když není co hlásit.", "Every weekday at 8:00, summarise the news on my reading list": "Každý pracovní den v 8:00 shrň zprávy z mého seznamu ke čtení", "Failed": "Selhalo", "Fewest": "Nejméně", "Files": "Soubory", + "Finished %(n)s": "Dokončeno: %(n)s", "Folder": "Složka", "Free space": "Volné místo", "Hello": "Dobrý den", "Hello, %(name)s": "Dobrý den, %(name)s", "History": "Historie", + "How many work on it at once, the run's own agent among them, on the same model.": "Kolik jich na ní pracuje současně, včetně vlastního agenta běhu, na stejném modelu.", "In your own words. The server reads them into a rule and an instruction, and shows you the next runs before anything is saved.": "Vlastními slovy. Server z nich vytvoří pravidlo a pokyn a před uložením vám ukáže další spuštění.", "Install LLeMbas %(version)s…": "Nainstalovat LLeMbas %(version)s…", "Instruction files": "Soubory s pokyny", "It has not run yet.": "Ještě neběžel.", - "Its own agent included. Above one, it can add members that do the work while it leads them.": "Včetně vlastního agenta. Při více než jednom může přidat členy, kteří dělají práci, zatímco je vede.", "LLeMbas %(version)s is available (this is %(current)s)": "Je k dispozici LLeMbas %(version)s (tohle je %(current)s)", "LLeMbas Desktop needs a LLeMbas 2.0 server or later.": "LLeMbas Desktop potřebuje server LLeMbas 2.0 nebo novější.", "Last run": "Poslední běh", @@ -153,7 +161,7 @@ const LEMBAS_I18N = { "No model is available to this account.": "Tomuto účtu není dostupný žádný model.", "No more runs": "Žádná další spuštění", "No project folder yet: the agent can open nothing on this computer.": "Zatím žádná složka projektu: agent na tomto počítači nemůže nic otevřít.", - "No team": "Bez týmu", + "None": "Žádný", "Not measured.": "Neměřeno.", "Not run yet": "Ještě neběžela", "Not yet": "Ještě ne", @@ -161,7 +169,7 @@ const LEMBAS_I18N = { "Nothing is scheduled.": "Nic není naplánováno.", "Nothing matches.": "Nic neodpovídá.", "Nothing running.": "Nic neběží.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.": "Na pozadí nic neběží. Pomocníci, příkazy a členové týmu se tu zobrazí, dokud pracují.", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Na pozadí nic neběží. Subagenti, členové týmu a příkazy na pozadí se tu zobrazí, dokud pracují.", "Nothing to report": "Nic k hlášení", "Nothing yet.": "Zatím nic.", "Notifications": "Upozornění", @@ -232,9 +240,13 @@ const LEMBAS_I18N = { "Stop %(name)s and the members under it? They leave the team.": "Zastavit %(name)s a členy pod ním? Opustí tým.", "Stop the agent": "Zastavit agenta", "Stopped.": "Zastaveno.", + "Subagent": "Podagent", + "Subagents": "Podagenti", + "Summarise the earlier turns now and send the summary in their place.": "Shrnout dřívější kola hned a posílat místo nich shrnutí.", "System prompt": "Systémový pokyn", "Taken in while it ran:": "Převzato během běhu:", - "Team: %(size)s of %(max)s agents": "Tým: %(size)s z %(max)s agentů", + "Team member": "Člen týmu", + "Team: %(size)s of at most %(max)s subagents": "Tým: %(size)s z nejvýše %(max)s subagentů", "Tell me": "Upozornit mě", "Tell me when a reply or an agent's work is finished while I am elsewhere": "Upozornit mě, když je odpověď nebo práce agenta hotová, zatímco jsem jinde", "The agent asks to run %(tool)s:": "Agent žádá o spuštění %(tool)s:", @@ -251,6 +263,7 @@ const LEMBAS_I18N = { "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does, and the same approval links this computer for the agent.": "Aplikace se k vašemu serveru přihlásí jednou, ve vašem prohlížeči, jako každé zařízení. Pak může číst a psát vaše konverzace, jako webové rozhraní, a stejné schválení propojí tento počítač pro agenta.", "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does.": "Aplikace se k vašemu serveru přihlásí jednou, ve vašem prohlížeči, jako každé zařízení. Pak může číst a psát vaše konverzace, jako webové rozhraní.", "The connection to the reply was lost: %(why)s": "Spojení s odpovědí se přerušilo: %(why)s", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Nejméně a nejvíce subagentů, které tato konverzace spouští. Pracují na stejném modelu, pokud v konverzaci nepojmenujete jiný.", "The first free scheduling model": "První volný model pro plánování", "The instruction each run is given, on its own: say everything it needs.": "Instrukce, kterou dostane každé spuštění samostatně: uveďte vše, co potřebuje.", "The last %(n)s runs failed: %(why)s": "Posledních %(n)s spuštění selhalo: %(why)s", @@ -269,6 +282,7 @@ const LEMBAS_I18N = { "This file is too large to send.": "Tento soubor je příliš velký na odeslání.", "This is a folder; attach the files in it.": "Toto je složka; přiložte soubory v ní.", "This is not a text file; it cannot be shown here.": "Toto není textový soubor; nelze ho zde zobrazit.", + "This server cannot compact a chat from the app yet; the web interface can.": "Tento server zatím neumí shrnout konverzaci z aplikace; webové rozhraní to umí.", "This server has no scheduled tasks yet.": "Tento server zatím nemá naplánované úlohy.", "Thought": "Přemýšlel", "Time": "Čas", @@ -278,6 +292,7 @@ const LEMBAS_I18N = { "Tools": "Nástroje", "Try again": "Zkusit znovu", "Type a command or a chat's title": "Napište příkaz nebo název konverzace", + "Up to %(n)s at once": "Nejvýše %(n)s současně", "Wait until the files are sent.": "Počkejte, až se soubory odešlou.", "Waiting for a free model": "Čeká na volný model", "Waiting for the browser…": "Čeká se na prohlížeč…", @@ -326,10 +341,11 @@ const LEMBAS_I18N = { }, "de": { "%(model)s was busy, so it ran on this one.": "%(model)s war belegt, daher lief sie auf diesem.", - "%(n)s agents working": "%(n)s Agenten arbeiten", "%(n)s finished": "%(n)s beendet", "%(n)s missed": "%(n)s verpasst", "%(n)s queued": "%(n)s in der Warteschlange", + "%(n)s running": "%(n)s laufen", + "%(n)s tasks": "%(n)s Aufgaben", "%(n)s tokens": "%(n)s Tokens", "%(n)s tools offered.": "%(n)s Werkzeuge angeboten.", "%(n)s waiting": "%(n)s warten", @@ -338,7 +354,8 @@ const LEMBAS_I18N = { "%(percent)s%% used": "%(percent)s %% belegt", "%(steps)s steps, %(tools)s tools": "%(steps)s Schritte, %(tools)s Werkzeuge", "%(tokens)s tokens": "%(tokens)s Tokens", - "1 agent working": "1 Agent arbeitet", + "%(tokens)s until auto-compact": "%(tokens)s bis zur automatischen Zusammenfassung", + "1 task": "1 Aufgabe", "A LLeMbas CLI service already runs here (pid %(pid)s), but is not connected: %(why)s": "Ein LLeMbas-CLI-Dienst läuft hier bereits (PID %(pid)s), ist aber nicht verbunden: %(why)s", "A LLeMbas CLI service already runs here (pid %(pid)s); it is this computer's agent.": "Ein LLeMbas-CLI-Dienst läuft hier bereits (PID %(pid)s); er ist der Agent dieses Computers.", "A busy model is waited for, then the next free one is used.": "Auf ein belegtes Modell wird gewartet, dann wird das nächste freie genommen.", @@ -351,8 +368,6 @@ const LEMBAS_I18N = { "A scheduled task has a result.": "Eine geplante Aufgabe hat ein Ergebnis.", "A shell as you, in one of these folders.": "Eine Shell als Sie, in einem dieser Ordner.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Eine Aufgabe ohne eigenes Modell läuft auf dem ersten freien davon, in dieser Reihenfolge. Keines angehakt: alle.", - "A team of up to %(n)s": "Ein Team mit bis zu %(n)s", - "A team works on it together, its own agent included.": "Ein Team arbeitet gemeinsam daran, ihr eigener Agent eingeschlossen.", "About": "Über", "Account": "Konto", "Activity": "Aktivität", @@ -361,7 +376,6 @@ const LEMBAS_I18N = { "Agent": "Agent", "Agent chats can work in these folders and anything inside them — nowhere else on this computer.": "Agenten-Chats können in diesen Ordnern und allem darin arbeiten — nirgendwo sonst auf diesem Computer.", "Agent: %(why)s": "Agent: %(why)s", - "Agents": "Agenten", "Allow": "Erlauben", "Always": "Immer", "Always allow": "Immer erlauben", @@ -372,7 +386,9 @@ const LEMBAS_I18N = { "Archive chat": "Chat archivieren", "Attach files": "Dateien anhängen", "Auto — asks nothing": "Auto — fragt nichts", + "Automatic compaction is off.": "Die automatische Zusammenfassung ist aus.", "Back": "Zurück", + "Background command": "Hintergrundbefehl", "Background tasks": "Hintergrundaufgaben", "Cancel": "Abbrechen", "Carry it out": "Ausführen", @@ -385,9 +401,14 @@ const LEMBAS_I18N = { "Close the activity panel": "Aktivitätsbereich schließen", "Command": "Befehl", "Commands": "Befehle", + "Compact": "Zusammenfassen", + "Compacting…": "Wird zusammengefasst…", "Compaction buffer": "Puffer für die Verdichtung", + "Compacts before the next reply.": "Wird vor der nächsten Antwort zusammengefasst.", + "Compacts by itself once the window is known.": "Wird von selbst zusammengefasst, sobald das Fenster bekannt ist.", "Connect": "Verbinden", "Context": "Kontext", + "Context and background tasks": "Kontext und Hintergrundaufgaben", "Continue in a terminal": "Im Terminal fortsetzen", "Continue in a terminal…": "Im Terminal fortsetzen…", "Copied": "Kopiert", @@ -413,22 +434,24 @@ const LEMBAS_I18N = { "Edit message": "Nachricht bearbeiten", "Edit — asks before commands": "Edit — fragt vor Befehlen", "Empty folder": "Leerer Ordner", + "Environment": "Umgebung", "Estimated: no reply has been counted yet.": "Geschätzt: Noch keine Antwort wurde gezählt.", "Every result, even with nothing to report.": "Jedes Ergebnis, auch ohne Neuigkeiten.", "Every weekday at 8:00, summarise the news on my reading list": "Jeden Werktag um 8:00 die Nachrichten auf meiner Leseliste zusammenfassen", "Failed": "Fehlgeschlagen", "Fewest": "Mindestens", "Files": "Dateien", + "Finished %(n)s": "Fertig: %(n)s", "Folder": "Ordner", "Free space": "Freier Platz", "Hello": "Hallo", "Hello, %(name)s": "Hallo, %(name)s", "History": "Verlauf", + "How many work on it at once, the run's own agent among them, on the same model.": "Wie viele gleichzeitig daran arbeiten, der eigene Agent des Laufs mitgezählt, mit demselben Modell.", "In your own words. The server reads them into a rule and an instruction, and shows you the next runs before anything is saved.": "In Ihren eigenen Worten. Der Server macht daraus eine Regel und eine Anweisung und zeigt Ihnen die nächsten Läufe, bevor etwas gespeichert wird.", "Install LLeMbas %(version)s…": "LLeMbas %(version)s installieren…", "Instruction files": "Anweisungsdateien", "It has not run yet.": "Er ist noch nicht gelaufen.", - "Its own agent included. Above one, it can add members that do the work while it leads them.": "Der eigene Agent eingeschlossen. Bei mehr als einem kann er Mitglieder hinzufügen, die die Arbeit machen, während er sie leitet.", "LLeMbas %(version)s is available (this is %(current)s)": "LLeMbas %(version)s ist verfügbar (dies ist %(current)s)", "LLeMbas Desktop needs a LLeMbas 2.0 server or later.": "LLeMbas Desktop braucht einen LLeMbas-Server 2.0 oder neuer.", "Last run": "Letzter Lauf", @@ -467,7 +490,7 @@ const LEMBAS_I18N = { "No model is available to this account.": "Diesem Konto steht kein Modell zur Verfügung.", "No more runs": "Keine weiteren Läufe", "No project folder yet: the agent can open nothing on this computer.": "Noch kein Projektordner: Der Agent kann auf diesem Computer nichts öffnen.", - "No team": "Kein Team", + "None": "Keiner", "Not measured.": "Nicht gemessen.", "Not run yet": "Noch nicht gelaufen", "Not yet": "Noch nicht", @@ -475,7 +498,7 @@ const LEMBAS_I18N = { "Nothing is scheduled.": "Nichts ist geplant.", "Nothing matches.": "Nichts gefunden.", "Nothing running.": "Nichts läuft.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.": "Im Hintergrund läuft nichts. Helfer, Befehle und die Mitglieder eines Teams erscheinen hier, solange sie arbeiten.", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Im Hintergrund läuft nichts. Subagenten, die Mitglieder eines Teams und Hintergrundbefehle erscheinen hier, solange sie arbeiten.", "Nothing to report": "Nichts zu melden", "Nothing yet.": "Noch nichts.", "Notifications": "Benachrichtigungen", @@ -546,9 +569,13 @@ const LEMBAS_I18N = { "Stop %(name)s and the members under it? They leave the team.": "%(name)s und die Mitglieder darunter stoppen? Sie verlassen das Team.", "Stop the agent": "Agent anhalten", "Stopped.": "Angehalten.", + "Subagent": "Subagent", + "Subagents": "Subagenten", + "Summarise the earlier turns now and send the summary in their place.": "Die früheren Runden jetzt zusammenfassen und stattdessen die Zusammenfassung senden.", "System prompt": "Systemprompt", "Taken in while it ran:": "Während des Laufs übernommen:", - "Team: %(size)s of %(max)s agents": "Team: %(size)s von %(max)s Agenten", + "Team member": "Teammitglied", + "Team: %(size)s of at most %(max)s subagents": "Team: %(size)s von höchstens %(max)s Subagenten", "Tell me": "Benachrichtigen", "Tell me when a reply or an agent's work is finished while I am elsewhere": "Benachrichtigen, wenn eine Antwort oder die Arbeit des Agenten fertig ist, während ich woanders bin", "The agent asks to run %(tool)s:": "Der Agent möchte %(tool)s ausführen:", @@ -565,6 +592,7 @@ const LEMBAS_I18N = { "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does, and the same approval links this computer for the agent.": "Die App meldet sich einmal an Ihrem Server an, in Ihrem Browser, wie jedes Gerät. Danach kann sie Ihre Chats lesen und schreiben, wie die Weboberfläche, und dieselbe Freigabe verbindet diesen Computer für den Agenten.", "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does.": "Die App meldet sich einmal an Ihrem Server an, in Ihrem Browser, wie jedes Gerät. Danach kann sie Ihre Chats lesen und schreiben, wie die Weboberfläche.", "The connection to the reply was lost: %(why)s": "Die Verbindung zur Antwort ist abgebrochen: %(why)s", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Die wenigsten und die meisten Subagenten, die dieser Chat startet. Sie arbeiten mit demselben Modell, außer Sie nennen im Chat ein anderes.", "The first free scheduling model": "Das erste freie Planungsmodell", "The instruction each run is given, on its own: say everything it needs.": "Die Anweisung, die jeder Lauf für sich erhält: Sagen Sie alles, was er braucht.", "The last %(n)s runs failed: %(why)s": "Die letzten %(n)s Läufe sind fehlgeschlagen: %(why)s", @@ -583,6 +611,7 @@ const LEMBAS_I18N = { "This file is too large to send.": "Diese Datei ist zu groß zum Senden.", "This is a folder; attach the files in it.": "Das ist ein Ordner; hängen Sie die Dateien darin an.", "This is not a text file; it cannot be shown here.": "Das ist keine Textdatei; sie kann hier nicht angezeigt werden.", + "This server cannot compact a chat from the app yet; the web interface can.": "Dieser Server kann einen Chat noch nicht aus der App zusammenfassen; die Weboberfläche kann es.", "This server has no scheduled tasks yet.": "Dieser Server hat noch keine geplanten Aufgaben.", "Thought": "Nachgedacht", "Time": "Uhrzeit", @@ -592,6 +621,7 @@ const LEMBAS_I18N = { "Tools": "Werkzeuge", "Try again": "Erneut versuchen", "Type a command or a chat's title": "Befehl oder Chat-Titel eingeben", + "Up to %(n)s at once": "Bis zu %(n)s gleichzeitig", "Wait until the files are sent.": "Warten Sie, bis die Dateien gesendet sind.", "Waiting for a free model": "Wartet auf ein freies Modell", "Waiting for the browser…": "Warte auf den Browser…", @@ -640,10 +670,11 @@ const LEMBAS_I18N = { }, "es": { "%(model)s was busy, so it ran on this one.": "%(model)s estaba ocupado, así que se ejecutó en este.", - "%(n)s agents working": "%(n)s agentes trabajando", "%(n)s finished": "%(n)s terminados", "%(n)s missed": "%(n)s perdidas", "%(n)s queued": "%(n)s en cola", + "%(n)s running": "%(n)s en marcha", + "%(n)s tasks": "%(n)s tareas", "%(n)s tokens": "tokens: %(n)s", "%(n)s tools offered.": "%(n)s herramientas ofrecidas.", "%(n)s waiting": "%(n)s esperando", @@ -652,7 +683,8 @@ const LEMBAS_I18N = { "%(percent)s%% used": "%(percent)s %% usado", "%(steps)s steps, %(tools)s tools": "%(steps)s pasos, %(tools)s herramientas", "%(tokens)s tokens": "%(tokens)s tokens", - "1 agent working": "1 agente trabajando", + "%(tokens)s until auto-compact": "%(tokens)s hasta la compactación automática", + "1 task": "1 tarea", "A LLeMbas CLI service already runs here (pid %(pid)s), but is not connected: %(why)s": "Ya hay un servicio de LLeMbas CLI aquí (pid %(pid)s), pero no está conectado: %(why)s", "A LLeMbas CLI service already runs here (pid %(pid)s); it is this computer's agent.": "Ya se está ejecutando aquí un servicio de LLeMbas CLI (pid %(pid)s); es el agente de este ordenador.", "A busy model is waited for, then the next free one is used.": "Se espera a un modelo ocupado y luego se usa el siguiente libre.", @@ -665,8 +697,6 @@ const LEMBAS_I18N = { "A scheduled task has a result.": "Una tarea programada tiene un resultado.", "A shell as you, in one of these folders.": "Un shell con su usuario, en una de estas carpetas.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Una tarea sin modelo propio se ejecuta en el primero libre de estos, en este orden. Ninguno marcado: todos.", - "A team of up to %(n)s": "Un equipo de hasta %(n)s", - "A team works on it together, its own agent included.": "Un equipo trabaja en ella, incluido su propio agente.", "About": "Acerca de", "Account": "Cuenta", "Activity": "Actividad", @@ -675,7 +705,6 @@ const LEMBAS_I18N = { "Agent": "Agente", "Agent chats can work in these folders and anything inside them — nowhere else on this computer.": "Los chats de agente pueden trabajar en estas carpetas y en todo lo que contienen — en ningún otro lugar de este equipo.", "Agent: %(why)s": "Agente: %(why)s", - "Agents": "Agentes", "Allow": "Permitir", "Always": "Siempre", "Always allow": "Permitir siempre", @@ -686,7 +715,9 @@ const LEMBAS_I18N = { "Archive chat": "Archivar chat", "Attach files": "Adjuntar archivos", "Auto — asks nothing": "Auto — no pregunta nada", + "Automatic compaction is off.": "La compactación automática está desactivada.", "Back": "Volver", + "Background command": "Comando en segundo plano", "Background tasks": "Tareas en segundo plano", "Cancel": "Cancelar", "Carry it out": "Llevarlo a cabo", @@ -699,9 +730,14 @@ const LEMBAS_I18N = { "Close the activity panel": "Cerrar el panel de actividad", "Command": "Comando", "Commands": "Comandos", + "Compact": "Compactar", + "Compacting…": "Compactando…", "Compaction buffer": "Reserva para la compactación", + "Compacts before the next reply.": "Se compacta antes de la próxima respuesta.", + "Compacts by itself once the window is known.": "Se compacta sola en cuanto se conozca la ventana.", "Connect": "Conectar", "Context": "Contexto", + "Context and background tasks": "Contexto y tareas en segundo plano", "Continue in a terminal": "Continuar en un terminal", "Continue in a terminal…": "Continuar en un terminal…", "Copied": "Copiado", @@ -727,22 +763,24 @@ const LEMBAS_I18N = { "Edit message": "Editar mensaje", "Edit — asks before commands": "Edit — pregunta antes de los comandos", "Empty folder": "Carpeta vacía", + "Environment": "Entorno", "Estimated: no reply has been counted yet.": "Estimado: aún no se ha contado ninguna respuesta.", "Every result, even with nothing to report.": "Cada resultado, incluso sin nada que informar.", "Every weekday at 8:00, summarise the news on my reading list": "Cada día laborable a las 8:00, resume las noticias de mi lista de lectura", "Failed": "Fallidos", "Fewest": "Mínimo", "Files": "Archivos", + "Finished %(n)s": "Terminadas: %(n)s", "Folder": "Carpeta", "Free space": "Espacio libre", "Hello": "Hola", "Hello, %(name)s": "Hola, %(name)s", "History": "Historial", + "How many work on it at once, the run's own agent among them, on the same model.": "Cuántos trabajan en ella a la vez, contando el propio agente de la ejecución, con el mismo modelo.", "In your own words. The server reads them into a rule and an instruction, and shows you the next runs before anything is saved.": "Con sus propias palabras. El servidor las convierte en una regla y una instrucción, y le muestra las próximas ejecuciones antes de guardar nada.", "Install LLeMbas %(version)s…": "Instalar LLeMbas %(version)s…", "Instruction files": "Archivos de instrucciones", "It has not run yet.": "Todavía no se ha ejecutado.", - "Its own agent included. Above one, it can add members that do the work while it leads them.": "Su propio agente incluido. Con más de uno, puede añadir miembros que hagan el trabajo mientras los dirige.", "LLeMbas %(version)s is available (this is %(current)s)": "LLeMbas %(version)s está disponible (esta es la %(current)s)", "LLeMbas Desktop needs a LLeMbas 2.0 server or later.": "LLeMbas Desktop necesita un servidor LLeMbas 2.0 o posterior.", "Last run": "Última ejecución", @@ -781,7 +819,7 @@ const LEMBAS_I18N = { "No model is available to this account.": "Ningún modelo está disponible para esta cuenta.", "No more runs": "No hay más ejecuciones", "No project folder yet: the agent can open nothing on this computer.": "Aún no hay carpeta de proyecto: el agente no puede abrir nada en este equipo.", - "No team": "Sin equipo", + "None": "Ninguno", "Not measured.": "Sin medir.", "Not run yet": "Aún no se ha ejecutado", "Not yet": "Todavía no", @@ -789,7 +827,7 @@ const LEMBAS_I18N = { "Nothing is scheduled.": "No hay nada programado.", "Nothing matches.": "No hay coincidencias.", "Nothing running.": "Nada en marcha.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.": "No hay nada en segundo plano. Los ayudantes, los comandos y los miembros de un equipo aparecen aquí mientras trabajan.", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "No hay nada en segundo plano. Los subagentes, los miembros de un equipo y los comandos en segundo plano aparecen aquí mientras trabajan.", "Nothing to report": "Nada que informar", "Nothing yet.": "Aún nada.", "Notifications": "Notificaciones", @@ -860,9 +898,13 @@ const LEMBAS_I18N = { "Stop %(name)s and the members under it? They leave the team.": "¿Detener %(name)s y a los miembros que dependen de él? Dejan el equipo.", "Stop the agent": "Detener el agente", "Stopped.": "Detenido.", + "Subagent": "Subagente", + "Subagents": "Subagentes", + "Summarise the earlier turns now and send the summary in their place.": "Resumir ahora los turnos anteriores y enviar el resumen en su lugar.", "System prompt": "Prompt de sistema", "Taken in while it ran:": "Incorporado mientras se ejecutaba:", - "Team: %(size)s of %(max)s agents": "Equipo: %(size)s de %(max)s agentes", + "Team member": "Miembro del equipo", + "Team: %(size)s of at most %(max)s subagents": "Equipo: %(size)s de un máximo de %(max)s subagentes", "Tell me": "Avisarme", "Tell me when a reply or an agent's work is finished while I am elsewhere": "Avisarme cuando una respuesta o el trabajo de un agente termine mientras estoy en otra parte", "The agent asks to run %(tool)s:": "El agente pide ejecutar %(tool)s:", @@ -879,6 +921,7 @@ const LEMBAS_I18N = { "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does, and the same approval links this computer for the agent.": "La aplicación inicia sesión en su servidor una vez, en su navegador, como cualquier dispositivo. Después puede leer y escribir sus chats, como la interfaz web, y la misma aprobación vincula este ordenador para el agente.", "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does.": "La aplicación inicia sesión en su servidor una vez, en su navegador, como cualquier dispositivo. Después puede leer y escribir sus chats, como la interfaz web.", "The connection to the reply was lost: %(why)s": "Se perdió la conexión con la respuesta: %(why)s", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "El mínimo y el máximo de subagentes que inicia este chat. Usan el mismo modelo, salvo que nombre otro en el chat.", "The first free scheduling model": "El primer modelo de programación libre", "The instruction each run is given, on its own: say everything it needs.": "La instrucción que recibe cada ejecución por sí sola: diga todo lo que necesita.", "The last %(n)s runs failed: %(why)s": "Las últimas %(n)s ejecuciones fallaron: %(why)s", @@ -897,6 +940,7 @@ const LEMBAS_I18N = { "This file is too large to send.": "Este archivo es demasiado grande para enviarlo.", "This is a folder; attach the files in it.": "Esto es una carpeta; adjunte los archivos que contiene.", "This is not a text file; it cannot be shown here.": "No es un archivo de texto; no se puede mostrar aquí.", + "This server cannot compact a chat from the app yet; the web interface can.": "Este servidor aún no puede compactar un chat desde la aplicación; la interfaz web sí puede.", "This server has no scheduled tasks yet.": "Este servidor aún no tiene tareas programadas.", "Thought": "Pensamiento", "Time": "Hora", @@ -906,6 +950,7 @@ const LEMBAS_I18N = { "Tools": "Herramientas", "Try again": "Reintentar", "Type a command or a chat's title": "Escriba un comando o el título de un chat", + "Up to %(n)s at once": "Hasta %(n)s a la vez", "Wait until the files are sent.": "Espere a que se envíen los archivos.", "Waiting for a free model": "Esperando un modelo libre", "Waiting for the browser…": "Esperando al navegador…", @@ -954,10 +999,11 @@ const LEMBAS_I18N = { }, "fr": { "%(model)s was busy, so it ran on this one.": "%(model)s était occupé, elle a donc tourné sur celui-ci.", - "%(n)s agents working": "%(n)s agents au travail", "%(n)s finished": "%(n)s terminés", "%(n)s missed": "%(n)s manquées", "%(n)s queued": "%(n)s en file d’attente", + "%(n)s running": "%(n)s en cours", + "%(n)s tasks": "%(n)s tâches", "%(n)s tokens": "%(n)s jetons", "%(n)s tools offered.": "%(n)s outils proposés.", "%(n)s waiting": "%(n)s en attente", @@ -966,7 +1012,8 @@ const LEMBAS_I18N = { "%(percent)s%% used": "%(percent)s %% utilisés", "%(steps)s steps, %(tools)s tools": "%(steps)s étapes, %(tools)s outils", "%(tokens)s tokens": "%(tokens)s jetons", - "1 agent working": "1 agent au travail", + "%(tokens)s until auto-compact": "%(tokens)s avant le compactage automatique", + "1 task": "1 tâche", "A LLeMbas CLI service already runs here (pid %(pid)s), but is not connected: %(why)s": "Un service LLeMbas CLI tourne déjà ici (pid %(pid)s), mais n'est pas connecté : %(why)s", "A LLeMbas CLI service already runs here (pid %(pid)s); it is this computer's agent.": "Un service LLeMbas CLI tourne déjà ici (pid %(pid)s) ; c'est l'agent de cet ordinateur.", "A busy model is waited for, then the next free one is used.": "Un modèle occupé est attendu, puis le suivant libre est utilisé.", @@ -979,8 +1026,6 @@ const LEMBAS_I18N = { "A scheduled task has a result.": "Une tâche planifiée a un résultat.", "A shell as you, in one of these folders.": "Un shell en votre nom, dans l'un de ces dossiers.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Une tâche sans modèle à elle tourne sur le premier libre de ceux-ci, dans cet ordre. Aucun coché : tous.", - "A team of up to %(n)s": "Une équipe jusqu'à %(n)s", - "A team works on it together, its own agent included.": "Une équipe y travaille ensemble, son propre agent compris.", "About": "À propos", "Account": "Compte", "Activity": "Activité", @@ -989,7 +1034,6 @@ const LEMBAS_I18N = { "Agent": "Agent", "Agent chats can work in these folders and anything inside them — nowhere else on this computer.": "Les discussions d'agent peuvent travailler dans ces dossiers et tout ce qu'ils contiennent — nulle part ailleurs sur cet ordinateur.", "Agent: %(why)s": "Agent : %(why)s", - "Agents": "Agents", "Allow": "Autoriser", "Always": "Toujours", "Always allow": "Toujours autoriser", @@ -1000,7 +1044,9 @@ const LEMBAS_I18N = { "Archive chat": "Archiver la conversation", "Attach files": "Joindre des fichiers", "Auto — asks nothing": "Auto — ne demande rien", + "Automatic compaction is off.": "Le compactage automatique est désactivé.", "Back": "Retour", + "Background command": "Commande en arrière-plan", "Background tasks": "Tâches en arrière-plan", "Cancel": "Annuler", "Carry it out": "Exécuter", @@ -1013,9 +1059,14 @@ const LEMBAS_I18N = { "Close the activity panel": "Fermer le panneau d’activité", "Command": "Commande", "Commands": "Commandes", + "Compact": "Compacter", + "Compacting…": "Compactage…", "Compaction buffer": "Réserve de compactage", + "Compacts before the next reply.": "Compacté avant la prochaine réponse.", + "Compacts by itself once the window is known.": "Compacté de lui-même dès que la fenêtre est connue.", "Connect": "Se connecter", "Context": "Contexte", + "Context and background tasks": "Contexte et tâches en arrière-plan", "Continue in a terminal": "Continuer dans un terminal", "Continue in a terminal…": "Continuer dans un terminal…", "Copied": "Copié", @@ -1041,22 +1092,24 @@ const LEMBAS_I18N = { "Edit message": "Modifier le message", "Edit — asks before commands": "Edit — demande avant les commandes", "Empty folder": "Dossier vide", + "Environment": "Environnement", "Estimated: no reply has been counted yet.": "Estimation : aucune réponse n’a encore été comptée.", "Every result, even with nothing to report.": "Chaque résultat, même sans rien à signaler.", "Every weekday at 8:00, summarise the news on my reading list": "Chaque jour ouvré à 8 h, résume les nouvelles de ma liste de lecture", "Failed": "Échecs", "Fewest": "Au moins", "Files": "Fichiers", + "Finished %(n)s": "Terminées : %(n)s", "Folder": "Dossier", "Free space": "Espace libre", "Hello": "Bonjour", "Hello, %(name)s": "Bonjour, %(name)s", "History": "Historique", + "How many work on it at once, the run's own agent among them, on the same model.": "Combien y travaillent à la fois, l’agent de l’exécution compris, avec le même modèle.", "In your own words. The server reads them into a rule and an instruction, and shows you the next runs before anything is saved.": "Avec vos propres mots. Le serveur en fait une règle et une instruction, et vous montre les prochaines exécutions avant que rien ne soit enregistré.", "Install LLeMbas %(version)s…": "Installer LLeMbas %(version)s…", "Instruction files": "Fichiers d’instructions", "It has not run yet.": "Elle ne s'est pas encore exécutée.", - "Its own agent included. Above one, it can add members that do the work while it leads them.": "Son propre agent compris. Au-delà d’un, il peut ajouter des membres qui font le travail pendant qu’il les dirige.", "LLeMbas %(version)s is available (this is %(current)s)": "LLeMbas %(version)s est disponible (ceci est la %(current)s)", "LLeMbas Desktop needs a LLeMbas 2.0 server or later.": "LLeMbas Desktop nécessite un serveur LLeMbas 2.0 ou plus récent.", "Last run": "Dernière exécution", @@ -1095,7 +1148,7 @@ const LEMBAS_I18N = { "No model is available to this account.": "Aucun modèle n'est disponible pour ce compte.", "No more runs": "Plus d’exécution prévue", "No project folder yet: the agent can open nothing on this computer.": "Aucun dossier de projet pour l'instant : l'agent ne peut rien ouvrir sur cet ordinateur.", - "No team": "Pas d'équipe", + "None": "Aucun", "Not measured.": "Non mesuré.", "Not run yet": "Pas encore exécutée", "Not yet": "Pas encore", @@ -1103,7 +1156,7 @@ const LEMBAS_I18N = { "Nothing is scheduled.": "Rien n’est planifié.", "Nothing matches.": "Aucun résultat.", "Nothing running.": "Rien en cours.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.": "Rien ne tourne en arrière-plan. Les assistants, les commandes et les membres d’une équipe s’affichent ici pendant qu’ils travaillent.", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Rien ne tourne en arrière-plan. Les sous-agents, les membres d’une équipe et les commandes en arrière-plan s’affichent ici pendant qu’ils travaillent.", "Nothing to report": "Rien à signaler", "Nothing yet.": "Rien pour l'instant.", "Notifications": "Notifications", @@ -1174,9 +1227,13 @@ const LEMBAS_I18N = { "Stop %(name)s and the members under it? They leave the team.": "Arrêter %(name)s et les membres qui en dépendent ? Ils quittent l’équipe.", "Stop the agent": "Arrêter l'agent", "Stopped.": "Arrêté.", + "Subagent": "Sous-agent", + "Subagents": "Sous-agents", + "Summarise the earlier turns now and send the summary in their place.": "Résumer maintenant les tours précédents et envoyer le résumé à leur place.", "System prompt": "Prompt système", "Taken in while it ran:": "Pris en compte pendant l'exécution :", - "Team: %(size)s of %(max)s agents": "Équipe : %(size)s agents sur %(max)s", + "Team member": "Membre de l’équipe", + "Team: %(size)s of at most %(max)s subagents": "Équipe : %(size)s sur %(max)s sous-agents au plus", "Tell me": "Me prévenir", "Tell me when a reply or an agent's work is finished while I am elsewhere": "Me prévenir quand une réponse ou le travail d'un agent est terminé pendant que je suis ailleurs", "The agent asks to run %(tool)s:": "L'agent demande à exécuter %(tool)s :", @@ -1193,6 +1250,7 @@ const LEMBAS_I18N = { "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does, and the same approval links this computer for the agent.": "L'application se connecte une fois à votre serveur, dans votre navigateur, comme tout appareil. Elle peut ensuite lire et écrire vos discussions, comme l'interface web, et la même approbation relie cet ordinateur pour l'agent.", "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does.": "L'application se connecte une fois à votre serveur, dans votre navigateur, comme tout appareil. Elle peut ensuite lire et écrire vos discussions, comme l'interface web.", "The connection to the reply was lost: %(why)s": "La connexion à la réponse a été perdue : %(why)s", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Le moins et le plus de sous-agents que lance cette conversation. Ils utilisent le même modèle, sauf si vous en nommez un autre dans la conversation.", "The first free scheduling model": "Le premier modèle de planification libre", "The instruction each run is given, on its own: say everything it needs.": "L'instruction donnée à chaque exécution, seule : dites tout ce dont elle a besoin.", "The last %(n)s runs failed: %(why)s": "Les %(n)s dernières exécutions ont échoué : %(why)s", @@ -1211,6 +1269,7 @@ const LEMBAS_I18N = { "This file is too large to send.": "Ce fichier est trop volumineux pour être envoyé.", "This is a folder; attach the files in it.": "C'est un dossier ; joignez les fichiers qu'il contient.", "This is not a text file; it cannot be shown here.": "Ce n'est pas un fichier texte ; il ne peut pas être affiché ici.", + "This server cannot compact a chat from the app yet; the web interface can.": "Ce serveur ne peut pas encore compacter une conversation depuis l’application ; l’interface web le peut.", "This server has no scheduled tasks yet.": "Ce serveur n’a pas encore de tâches planifiées.", "Thought": "Réflexion", "Time": "Heure", @@ -1220,6 +1279,7 @@ const LEMBAS_I18N = { "Tools": "Outils", "Try again": "Réessayer", "Type a command or a chat's title": "Tapez une commande ou le titre d'une conversation", + "Up to %(n)s at once": "Jusqu’à %(n)s à la fois", "Wait until the files are sent.": "Attendez que les fichiers soient envoyés.", "Waiting for a free model": "En attente d’un modèle libre", "Waiting for the browser…": "En attente du navigateur…", @@ -1268,10 +1328,11 @@ const LEMBAS_I18N = { }, "hu": { "%(model)s was busy, so it ran on this one.": "%(model)s foglalt volt, ezért ezen futott.", - "%(n)s agents working": "%(n)s ügynök dolgozik", "%(n)s finished": "%(n)s befejezve", "%(n)s missed": "%(n)s kimaradt", "%(n)s queued": "%(n)s sorban áll", + "%(n)s running": "%(n)s fut", + "%(n)s tasks": "%(n)s feladat", "%(n)s tokens": "%(n)s token", "%(n)s tools offered.": "%(n)s eszköz felkínálva.", "%(n)s waiting": "%(n)s várakozik", @@ -1280,7 +1341,8 @@ const LEMBAS_I18N = { "%(percent)s%% used": "%(percent)s%% foglalt", "%(steps)s steps, %(tools)s tools": "%(steps)s lépés, %(tools)s eszköz", "%(tokens)s tokens": "%(tokens)s token", - "1 agent working": "1 ügynök dolgozik", + "%(tokens)s until auto-compact": "%(tokens)s az automatikus tömörítésig", + "1 task": "1 feladat", "A LLeMbas CLI service already runs here (pid %(pid)s), but is not connected: %(why)s": "Egy LLeMbas CLI szolgáltatás már fut itt (pid %(pid)s), de nincs csatlakozva: %(why)s", "A LLeMbas CLI service already runs here (pid %(pid)s); it is this computer's agent.": "Itt már fut egy LLeMbas CLI szolgáltatás (pid %(pid)s); ez a számítógép ügynöke.", "A busy model is waited for, then the next free one is used.": "A foglalt modellre vár, majd a következő szabadot használja.", @@ -1293,8 +1355,6 @@ const LEMBAS_I18N = { "A scheduled task has a result.": "Egy ütemezett feladatnak eredménye van.", "A shell as you, in one of these folders.": "Egy shell az Ön nevében, ezek egyik mappájában.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "A saját modell nélküli feladat ezek közül az első szabadon fut, ebben a sorrendben. Ha egy sincs bejelölve: mindegyiken.", - "A team of up to %(n)s": "Legfeljebb %(n)s fős csapat", - "A team works on it together, its own agent included.": "Egy csapat dolgozik rajta együtt, a saját ügynökét is beleértve.", "About": "Névjegy", "Account": "Fiók", "Activity": "Tevékenység", @@ -1303,7 +1363,6 @@ const LEMBAS_I18N = { "Agent": "Ügynök", "Agent chats can work in these folders and anything inside them — nowhere else on this computer.": "Az ügynökcsevegések ezekben a mappákban és mindenben, ami bennük van, dolgozhatnak — sehol máshol ezen a számítógépen.", "Agent: %(why)s": "Ügynök: %(why)s", - "Agents": "Ügynökök", "Allow": "Engedélyezés", "Always": "Mindig", "Always allow": "Mindig engedélyez", @@ -1314,7 +1373,9 @@ const LEMBAS_I18N = { "Archive chat": "Csevegés archiválása", "Attach files": "Fájlok csatolása", "Auto — asks nothing": "Auto — semmit nem kérdez", + "Automatic compaction is off.": "Az automatikus tömörítés ki van kapcsolva.", "Back": "Vissza", + "Background command": "Háttérparancs", "Background tasks": "Háttérfeladatok", "Cancel": "Mégse", "Carry it out": "Végrehajtás", @@ -1327,9 +1388,14 @@ const LEMBAS_I18N = { "Close the activity panel": "A tevékenységpanel bezárása", "Command": "Parancs", "Commands": "Parancsok", + "Compact": "Tömörítés", + "Compacting…": "Tömörítés…", "Compaction buffer": "Tömörítési tartalék", + "Compacts before the next reply.": "A következő válasz előtt tömörül.", + "Compacts by itself once the window is known.": "Magától tömörül, amint ismert az ablak.", "Connect": "Csatlakozás", "Context": "Kontextus", + "Context and background tasks": "Kontextus és háttérfeladatok", "Continue in a terminal": "Folytatás terminálban", "Continue in a terminal…": "Folytatás terminálban…", "Copied": "Másolva", @@ -1355,22 +1421,24 @@ const LEMBAS_I18N = { "Edit message": "Üzenet szerkesztése", "Edit — asks before commands": "Edit — parancsok előtt kérdez", "Empty folder": "Üres mappa", + "Environment": "Környezet", "Estimated: no reply has been counted yet.": "Becslés: még egy válasz sem lett megszámolva.", "Every result, even with nothing to report.": "Minden eredmény, akkor is, ha nincs mit jelenteni.", "Every weekday at 8:00, summarise the news on my reading list": "Minden hétköznap 8:00-kor foglald össze az olvasólistám híreit", "Failed": "Sikertelen", "Fewest": "Legalább", "Files": "Fájlok", + "Finished %(n)s": "Kész: %(n)s", "Folder": "Mappa", "Free space": "Szabad hely", "Hello": "Üdv", "Hello, %(name)s": "Üdv, %(name)s", "History": "Előzmények", + "How many work on it at once, the run's own agent among them, on the same model.": "Hányan dolgoznak rajta egyszerre, a futás saját ügynökét is beleértve, ugyanazon a modellen.", "In your own words. The server reads them into a rule and an instruction, and shows you the next runs before anything is saved.": "A saját szavaival. A szerver szabályt és utasítást készít belőlük, és mentés előtt megmutatja a következő futásokat.", "Install LLeMbas %(version)s…": "LLeMbas %(version)s telepítése…", "Instruction files": "Utasításfájlok", "It has not run yet.": "Még nem futott.", - "Its own agent included. Above one, it can add members that do the work while it leads them.": "A saját ügynökét is beleértve. Egynél több esetén tagokat vehet fel, akik elvégzik a munkát, amíg ő vezeti őket.", "LLeMbas %(version)s is available (this is %(current)s)": "Elérhető a LLeMbas %(version)s (ez a %(current)s)", "LLeMbas Desktop needs a LLeMbas 2.0 server or later.": "A LLeMbas Desktophoz LLeMbas 2.0 vagy újabb szerver kell.", "Last run": "Utolsó futtatás", @@ -1409,7 +1477,7 @@ const LEMBAS_I18N = { "No model is available to this account.": "Ennek a fióknak nem érhető el modell.", "No more runs": "Nincs több futás", "No project folder yet: the agent can open nothing on this computer.": "Még nincs projektmappa: az ügynök semmit sem nyithat meg ezen a számítógépen.", - "No team": "Nincs csapat", + "None": "Nincs", "Not measured.": "Nincs mérve.", "Not run yet": "Még nem futott", "Not yet": "Még nem", @@ -1417,7 +1485,7 @@ const LEMBAS_I18N = { "Nothing is scheduled.": "Nincs semmi ütemezve.", "Nothing matches.": "Nincs találat.", "Nothing running.": "Semmi sem fut.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.": "A háttérben semmi sem fut. A segítők, a parancsok és egy csapat tagjai itt jelennek meg, amíg dolgoznak.", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "A háttérben semmi sem fut. Az alügynökök, egy csapat tagjai és a háttérparancsok itt jelennek meg, amíg dolgoznak.", "Nothing to report": "Nincs jelentenivaló", "Nothing yet.": "Még semmi.", "Notifications": "Értesítések", @@ -1488,9 +1556,13 @@ const LEMBAS_I18N = { "Stop %(name)s and the members under it? They leave the team.": "Leállítja %(name)s tagot és az alatta lévőket? Kilépnek a csapatból.", "Stop the agent": "Ügynök leállítása", "Stopped.": "Leállítva.", + "Subagent": "Alügynök", + "Subagents": "Alügynökök", + "Summarise the earlier turns now and send the summary in their place.": "A korábbi köröket most összefoglalja, és helyettük az összefoglalót küldi.", "System prompt": "Rendszerprompt", "Taken in while it ran:": "Futás közben átvéve:", - "Team: %(size)s of %(max)s agents": "Csapat: %(size)s / %(max)s ügynök", + "Team member": "Csapattag", + "Team: %(size)s of at most %(max)s subagents": "Csapat: %(size)s a legfeljebb %(max)s alügynökből", "Tell me": "Értesítés", "Tell me when a reply or an agent's work is finished while I am elsewhere": "Szóljon, ha egy válasz vagy az ügynök munkája elkészül, amíg máshol vagyok", "The agent asks to run %(tool)s:": "Az ügynök a(z) %(tool)s futtatását kéri:", @@ -1507,6 +1579,7 @@ const LEMBAS_I18N = { "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does, and the same approval links this computer for the agent.": "Az alkalmazás egyszer jelentkezik be a szerverére, a böngészőjében, mint bármely eszköz. Ezután olvashatja és írhatja a csevegéseit, mint a webes felület, és ugyanez a jóváhagyás összekapcsolja ezt a számítógépet az ügynök számára.", "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does.": "Az alkalmazás egyszer jelentkezik be a szerverére, a böngészőjében, mint bármely eszköz. Ezután olvashatja és írhatja a csevegéseit, mint a webes felület.", "The connection to the reply was lost: %(why)s": "A kapcsolat a válasszal megszakadt: %(why)s", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "A beszélgetés által indított alügynökök legkisebb és legnagyobb száma. Ugyanazon a modellen dolgoznak, hacsak nem nevez meg másikat a beszélgetésben.", "The first free scheduling model": "Az első szabad ütemezési modell", "The instruction each run is given, on its own: say everything it needs.": "Az utasítás, amelyet minden futás önmagában kap: mondjon el mindent, amire szüksége van.", "The last %(n)s runs failed: %(why)s": "Az utolsó %(n)s futás sikertelen: %(why)s", @@ -1525,6 +1598,7 @@ const LEMBAS_I18N = { "This file is too large to send.": "Ez a fájl túl nagy a küldéshez.", "This is a folder; attach the files in it.": "Ez egy mappa; a benne lévő fájlokat csatolja.", "This is not a text file; it cannot be shown here.": "Ez nem szövegfájl; itt nem jeleníthető meg.", + "This server cannot compact a chat from the app yet; the web interface can.": "Ez a szerver még nem tud beszélgetést tömöríteni az alkalmazásból; a webes felület tud.", "This server has no scheduled tasks yet.": "Ezen a szerveren még nincsenek ütemezett feladatok.", "Thought": "Gondolkodott", "Time": "Időpont", @@ -1534,6 +1608,7 @@ const LEMBAS_I18N = { "Tools": "Eszközök", "Try again": "Újrapróbálás", "Type a command or a chat's title": "Írjon be egy parancsot vagy egy csevegés címét", + "Up to %(n)s at once": "Legfeljebb %(n)s egyszerre", "Wait until the files are sent.": "Várjon, amíg a fájlok elküldődnek.", "Waiting for a free model": "Szabad modellre vár", "Waiting for the browser…": "Várakozás a böngészőre…", @@ -1582,10 +1657,11 @@ const LEMBAS_I18N = { }, "it": { "%(model)s was busy, so it ran on this one.": "%(model)s era occupato, quindi è stata eseguita su questo.", - "%(n)s agents working": "%(n)s agenti al lavoro", "%(n)s finished": "%(n)s terminati", "%(n)s missed": "%(n)s perse", "%(n)s queued": "%(n)s in coda", + "%(n)s running": "%(n)s in corso", + "%(n)s tasks": "%(n)s attività", "%(n)s tokens": "token: %(n)s", "%(n)s tools offered.": "%(n)s strumenti offerti.", "%(n)s waiting": "%(n)s in attesa", @@ -1594,7 +1670,8 @@ const LEMBAS_I18N = { "%(percent)s%% used": "%(percent)s%% usato", "%(steps)s steps, %(tools)s tools": "%(steps)s passi, %(tools)s strumenti", "%(tokens)s tokens": "%(tokens)s token", - "1 agent working": "1 agente al lavoro", + "%(tokens)s until auto-compact": "%(tokens)s alla compattazione automatica", + "1 task": "1 attività", "A LLeMbas CLI service already runs here (pid %(pid)s), but is not connected: %(why)s": "Un servizio LLeMbas CLI è già in esecuzione qui (pid %(pid)s), ma non è collegato: %(why)s", "A LLeMbas CLI service already runs here (pid %(pid)s); it is this computer's agent.": "Un servizio LLeMbas CLI è già in esecuzione qui (pid %(pid)s); è l'agente di questo computer.", "A busy model is waited for, then the next free one is used.": "Si attende un modello occupato, poi si usa il successivo libero.", @@ -1607,8 +1684,6 @@ const LEMBAS_I18N = { "A scheduled task has a result.": "Un’attività pianificata ha un risultato.", "A shell as you, in one of these folders.": "Una shell con il tuo utente, in una di queste cartelle.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Un’attività senza un modello proprio gira sul primo libero di questi, in quest’ordine. Nessuno spuntato: tutti.", - "A team of up to %(n)s": "Un team fino a %(n)s", - "A team works on it together, its own agent included.": "Un team ci lavora insieme, incluso il suo agente.", "About": "Informazioni", "Account": "Account", "Activity": "Attività", @@ -1617,7 +1692,6 @@ const LEMBAS_I18N = { "Agent": "Agente", "Agent chats can work in these folders and anything inside them — nowhere else on this computer.": "Le chat con agente possono lavorare in queste cartelle e in tutto ciò che contengono — in nessun altro punto di questo computer.", "Agent: %(why)s": "Agente: %(why)s", - "Agents": "Agenti", "Allow": "Consenti", "Always": "Sempre", "Always allow": "Consenti sempre", @@ -1628,7 +1702,9 @@ const LEMBAS_I18N = { "Archive chat": "Archivia chat", "Attach files": "Allegare file", "Auto — asks nothing": "Auto — non chiede nulla", + "Automatic compaction is off.": "La compattazione automatica è disattivata.", "Back": "Indietro", + "Background command": "Comando in background", "Background tasks": "Attività in background", "Cancel": "Annulla", "Carry it out": "Eseguilo", @@ -1641,9 +1717,14 @@ const LEMBAS_I18N = { "Close the activity panel": "Chiudi il pannello attività", "Command": "Comando", "Commands": "Comandi", + "Compact": "Compatta", + "Compacting…": "Compattazione…", "Compaction buffer": "Riserva per la compattazione", + "Compacts before the next reply.": "Si compatta prima della prossima risposta.", + "Compacts by itself once the window is known.": "Si compatta da sola appena la finestra è nota.", "Connect": "Connetti", "Context": "Contesto", + "Context and background tasks": "Contesto e attività in background", "Continue in a terminal": "Continua in un terminale", "Continue in a terminal…": "Continua in un terminale…", "Copied": "Copiato", @@ -1669,22 +1750,24 @@ const LEMBAS_I18N = { "Edit message": "Modifica messaggio", "Edit — asks before commands": "Edit — chiede prima dei comandi", "Empty folder": "Cartella vuota", + "Environment": "Ambiente", "Estimated: no reply has been counted yet.": "Stima: nessuna risposta è stata ancora contata.", "Every result, even with nothing to report.": "Ogni risultato, anche senza nulla da segnalare.", "Every weekday at 8:00, summarise the news on my reading list": "Ogni giorno feriale alle 8:00, riassumi le notizie della mia lista di lettura", "Failed": "Non riusciti", "Fewest": "Minimo", "Files": "File", + "Finished %(n)s": "Terminate: %(n)s", "Folder": "Cartella", "Free space": "Spazio libero", "Hello": "Ciao", "Hello, %(name)s": "Ciao, %(name)s", "History": "Cronologia", + "How many work on it at once, the run's own agent among them, on the same model.": "Quanti ci lavorano alla volta, compreso l’agente dell’esecuzione, sullo stesso modello.", "In your own words. The server reads them into a rule and an instruction, and shows you the next runs before anything is saved.": "Con parole tue. Il server ne ricava una regola e un’istruzione e ti mostra le prossime esecuzioni prima di salvare.", "Install LLeMbas %(version)s…": "Installa LLeMbas %(version)s…", "Instruction files": "File di istruzioni", "It has not run yet.": "Non è ancora stata eseguita.", - "Its own agent included. Above one, it can add members that do the work while it leads them.": "Il proprio agente compreso. Con più di uno, può aggiungere membri che fanno il lavoro mentre li guida.", "LLeMbas %(version)s is available (this is %(current)s)": "È disponibile LLeMbas %(version)s (questa è la %(current)s)", "LLeMbas Desktop needs a LLeMbas 2.0 server or later.": "LLeMbas Desktop richiede un server LLeMbas 2.0 o successivo.", "Last run": "Ultima esecuzione", @@ -1723,7 +1806,7 @@ const LEMBAS_I18N = { "No model is available to this account.": "Nessun modello è disponibile per questo account.", "No more runs": "Nessun’altra esecuzione", "No project folder yet: the agent can open nothing on this computer.": "Nessuna cartella di progetto ancora: l'agente non può aprire nulla su questo computer.", - "No team": "Nessun team", + "None": "Nessuno", "Not measured.": "Non misurato.", "Not run yet": "Non ancora eseguita", "Not yet": "Non ancora", @@ -1731,7 +1814,7 @@ const LEMBAS_I18N = { "Nothing is scheduled.": "Non c’è niente di pianificato.", "Nothing matches.": "Nessun risultato.", "Nothing running.": "Nulla in esecuzione.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.": "Nulla è in esecuzione in background. Aiutanti, comandi e membri di una squadra compaiono qui mentre lavorano.", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Nulla è in esecuzione in background. Subagenti, membri di una squadra e comandi in background compaiono qui mentre lavorano.", "Nothing to report": "Niente da segnalare", "Nothing yet.": "Ancora niente.", "Notifications": "Notifiche", @@ -1802,9 +1885,13 @@ const LEMBAS_I18N = { "Stop %(name)s and the members under it? They leave the team.": "Fermare %(name)s e i membri sotto di lui? Lasciano la squadra.", "Stop the agent": "Ferma l'agente", "Stopped.": "Interrotto.", + "Subagent": "Sottoagente", + "Subagents": "Sottoagenti", + "Summarise the earlier turns now and send the summary in their place.": "Riassumi ora i turni precedenti e invia il riassunto al loro posto.", "System prompt": "Prompt di sistema", "Taken in while it ran:": "Accolto durante l'esecuzione:", - "Team: %(size)s of %(max)s agents": "Squadra: %(size)s di %(max)s agenti", + "Team member": "Membro della squadra", + "Team: %(size)s of at most %(max)s subagents": "Squadra: %(size)s su un massimo di %(max)s subagenti", "Tell me": "Avvisami", "Tell me when a reply or an agent's work is finished while I am elsewhere": "Avvisami quando una risposta o il lavoro di un agente è finito mentre sono altrove", "The agent asks to run %(tool)s:": "L'agente chiede di eseguire %(tool)s:", @@ -1821,6 +1908,7 @@ const LEMBAS_I18N = { "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does, and the same approval links this computer for the agent.": "L'app accede al suo server una volta, nel suo browser, come ogni dispositivo. Poi può leggere e scrivere le sue chat, come l'interfaccia web, e la stessa approvazione collega questo computer per l'agente.", "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does.": "L'app accede al suo server una volta, nel suo browser, come ogni dispositivo. Poi può leggere e scrivere le sue chat, come l'interfaccia web.", "The connection to the reply was lost: %(why)s": "La connessione alla risposta si è interrotta: %(why)s", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Il minimo e il massimo di subagenti che questa chat avvia. Lavorano sullo stesso modello, a meno che tu ne nomini un altro nella chat.", "The first free scheduling model": "Il primo modello di pianificazione libero", "The instruction each run is given, on its own: say everything it needs.": "L’istruzione che ogni esecuzione riceve da sola: di’ tutto ciò che le serve.", "The last %(n)s runs failed: %(why)s": "Le ultime %(n)s esecuzioni non sono riuscite: %(why)s", @@ -1839,6 +1927,7 @@ const LEMBAS_I18N = { "This file is too large to send.": "Questo file è troppo grande per essere inviato.", "This is a folder; attach the files in it.": "Questa è una cartella; alleghi i file che contiene.", "This is not a text file; it cannot be shown here.": "Questo non è un file di testo; non può essere mostrato qui.", + "This server cannot compact a chat from the app yet; the web interface can.": "Questo server non può ancora compattare una chat dall’app; l’interfaccia web sì.", "This server has no scheduled tasks yet.": "Questo server non ha ancora attività pianificate.", "Thought": "Ha ragionato", "Time": "Ora", @@ -1848,6 +1937,7 @@ const LEMBAS_I18N = { "Tools": "Strumenti", "Try again": "Riprova", "Type a command or a chat's title": "Digiti un comando o il titolo di una chat", + "Up to %(n)s at once": "Fino a %(n)s alla volta", "Wait until the files are sent.": "Attenda che i file siano inviati.", "Waiting for a free model": "In attesa di un modello libero", "Waiting for the browser…": "In attesa del browser…", @@ -1896,10 +1986,11 @@ const LEMBAS_I18N = { }, "pl": { "%(model)s was busy, so it ran on this one.": "%(model)s był zajęty, więc uruchomiono je na tym.", - "%(n)s agents working": "Pracujący agenci: %(n)s", "%(n)s finished": "Zakończone: %(n)s", "%(n)s missed": "pominięte: %(n)s", "%(n)s queued": "W kolejce: %(n)s", + "%(n)s running": "Działa: %(n)s", + "%(n)s tasks": "Zadania: %(n)s", "%(n)s tokens": "Tokeny: %(n)s", "%(n)s tools offered.": "Oferowane narzędzia: %(n)s.", "%(n)s waiting": "Czeka: %(n)s", @@ -1908,7 +1999,8 @@ const LEMBAS_I18N = { "%(percent)s%% used": "Użyto: %(percent)s%%", "%(steps)s steps, %(tools)s tools": "Kroki: %(steps)s, narzędzia: %(tools)s", "%(tokens)s tokens": "Tokeny: %(tokens)s", - "1 agent working": "1 agent pracuje", + "%(tokens)s until auto-compact": "%(tokens)s do automatycznego streszczenia", + "1 task": "1 zadanie", "A LLeMbas CLI service already runs here (pid %(pid)s), but is not connected: %(why)s": "Usługa LLeMbas CLI już tu działa (pid %(pid)s), ale nie jest połączona: %(why)s", "A LLeMbas CLI service already runs here (pid %(pid)s); it is this computer's agent.": "Usługa LLeMbas CLI już tu działa (pid %(pid)s); jest agentem tego komputera.", "A busy model is waited for, then the next free one is used.": "Na zajęty model się czeka, potem używany jest następny wolny.", @@ -1921,8 +2013,6 @@ const LEMBAS_I18N = { "A scheduled task has a result.": "Zaplanowane zadanie ma wynik.", "A shell as you, in one of these folders.": "Powłoka na Twoim koncie, w jednym z tych folderów.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Zadanie bez własnego modelu działa na pierwszym wolnym z tych, w tej kolejności. Żaden niezaznaczony: wszystkie.", - "A team of up to %(n)s": "Zespół do %(n)s", - "A team works on it together, its own agent included.": "Pracuje nad nim zespół, wraz z jego własnym agentem.", "About": "O aplikacji", "Account": "Konto", "Activity": "Aktywność", @@ -1931,7 +2021,6 @@ const LEMBAS_I18N = { "Agent": "Agent", "Agent chats can work in these folders and anything inside them — nowhere else on this computer.": "Czaty z agentem mogą pracować w tych folderach i we wszystkim, co zawierają — nigdzie indziej na tym komputerze.", "Agent: %(why)s": "Agent: %(why)s", - "Agents": "Agenci", "Allow": "Pozwól", "Always": "Zawsze", "Always allow": "Zawsze zezwalaj", @@ -1942,7 +2031,9 @@ const LEMBAS_I18N = { "Archive chat": "Archiwizuj czat", "Attach files": "Załączaj pliki", "Auto — asks nothing": "Auto — o nic nie pyta", + "Automatic compaction is off.": "Automatyczne streszczanie jest wyłączone.", "Back": "Wstecz", + "Background command": "Polecenie w tle", "Background tasks": "Zadania w tle", "Cancel": "Anuluj", "Carry it out": "Wykonaj", @@ -1955,9 +2046,14 @@ const LEMBAS_I18N = { "Close the activity panel": "Zamknij panel aktywności", "Command": "Polecenie", "Commands": "Polecenia", + "Compact": "Streść", + "Compacting…": "Streszczanie…", "Compaction buffer": "Rezerwa na kompakcję", + "Compacts before the next reply.": "Zostanie streszczona przed następną odpowiedzią.", + "Compacts by itself once the window is known.": "Zostanie streszczona sama, gdy okno będzie znane.", "Connect": "Połącz", "Context": "Kontekst", + "Context and background tasks": "Kontekst i zadania w tle", "Continue in a terminal": "Kontynuuj w terminalu", "Continue in a terminal…": "Kontynuuj w terminalu…", "Copied": "Skopiowano", @@ -1983,22 +2079,24 @@ const LEMBAS_I18N = { "Edit message": "Edytuj wiadomość", "Edit — asks before commands": "Edit — pyta przed poleceniami", "Empty folder": "Pusty folder", + "Environment": "Środowisko", "Estimated: no reply has been counted yet.": "Szacunek: żadna odpowiedź nie została jeszcze policzona.", "Every result, even with nothing to report.": "Każdy wynik, nawet bez niczego do zgłoszenia.", "Every weekday at 8:00, summarise the news on my reading list": "W każdy dzień roboczy o 8:00 streść wiadomości z mojej listy do czytania", "Failed": "Nieudane", "Fewest": "Najmniej", "Files": "Pliki", + "Finished %(n)s": "Zakończone: %(n)s", "Folder": "Folder", "Free space": "Wolne miejsce", "Hello": "Cześć", "Hello, %(name)s": "Cześć, %(name)s", "History": "Historia", + "How many work on it at once, the run's own agent among them, on the same model.": "Ilu pracuje nad nim naraz, łącznie z własnym agentem uruchomienia, na tym samym modelu.", "In your own words. The server reads them into a rule and an instruction, and shows you the next runs before anything is saved.": "Własnymi słowami. Serwer zamieni je w regułę i polecenie i pokaże następne uruchomienia, zanim cokolwiek zostanie zapisane.", "Install LLeMbas %(version)s…": "Zainstaluj LLeMbas %(version)s…", "Instruction files": "Pliki z instrukcjami", "It has not run yet.": "Jeszcze się nie uruchomił.", - "Its own agent included. Above one, it can add members that do the work while it leads them.": "Wliczając własnego agenta. Przy więcej niż jednym może dodać członków, którzy wykonują pracę, gdy on nimi kieruje.", "LLeMbas %(version)s is available (this is %(current)s)": "Dostępny jest LLeMbas %(version)s (to jest %(current)s)", "LLeMbas Desktop needs a LLeMbas 2.0 server or later.": "LLeMbas Desktop wymaga serwera LLeMbas 2.0 lub nowszego.", "Last run": "Ostatni przebieg", @@ -2037,7 +2135,7 @@ const LEMBAS_I18N = { "No model is available to this account.": "Dla tego konta nie jest dostępny żaden model.", "No more runs": "Brak kolejnych uruchomień", "No project folder yet: the agent can open nothing on this computer.": "Jeszcze nie ma folderu projektu: agent nie może niczego otworzyć na tym komputerze.", - "No team": "Bez zespołu", + "None": "Brak", "Not measured.": "Nie zmierzono.", "Not run yet": "Jeszcze nie uruchomione", "Not yet": "Jeszcze nie", @@ -2045,7 +2143,7 @@ const LEMBAS_I18N = { "Nothing is scheduled.": "Nic nie jest zaplanowane.", "Nothing matches.": "Nic nie pasuje.", "Nothing running.": "Nic nie działa.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.": "W tle nic nie działa. Pomocnicy, polecenia i członkowie zespołu pojawiają się tu, gdy pracują.", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "W tle nic nie działa. Subagenci, członkowie zespołu i polecenia w tle pojawiają się tu, gdy pracują.", "Nothing to report": "Nic do zgłoszenia", "Nothing yet.": "Jeszcze nic.", "Notifications": "Powiadomienia", @@ -2116,9 +2214,13 @@ const LEMBAS_I18N = { "Stop %(name)s and the members under it? They leave the team.": "Zatrzymać %(name)s i członków pod nim? Opuszczą zespół.", "Stop the agent": "Zatrzymaj agenta", "Stopped.": "Zatrzymano.", + "Subagent": "Podagent", + "Subagents": "Podagenci", + "Summarise the earlier turns now and send the summary in their place.": "Streścić teraz wcześniejsze tury i wysyłać streszczenie zamiast nich.", "System prompt": "Prompt systemowy", "Taken in while it ran:": "Przejęte w trakcie działania:", - "Team: %(size)s of %(max)s agents": "Zespół: %(size)s z %(max)s agentów", + "Team member": "Członek zespołu", + "Team: %(size)s of at most %(max)s subagents": "Zespół: %(size)s z najwyżej %(max)s subagentów", "Tell me": "Powiadamiaj", "Tell me when a reply or an agent's work is finished while I am elsewhere": "Powiadom mnie, gdy odpowiedź lub praca agenta jest gotowa, a ja jestem gdzie indziej", "The agent asks to run %(tool)s:": "Agent prosi o uruchomienie %(tool)s:", @@ -2135,6 +2237,7 @@ const LEMBAS_I18N = { "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does, and the same approval links this computer for the agent.": "Aplikacja loguje się do Twojego serwera raz, w przeglądarce, jak każde urządzenie. Potem może czytać i pisać Twoje czaty, jak interfejs WWW, a to samo zatwierdzenie łączy ten komputer dla agenta.", "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does.": "Aplikacja loguje się do Twojego serwera raz, w przeglądarce, jak każde urządzenie. Potem może czytać i pisać Twoje czaty, jak interfejs WWW.", "The connection to the reply was lost: %(why)s": "Połączenie z odpowiedzią zostało zerwane: %(why)s", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Najmniej i najwięcej subagentów, których uruchamia ten czat. Pracują na tym samym modelu, chyba że w czacie wskażesz inny.", "The first free scheduling model": "Pierwszy wolny model do planowania", "The instruction each run is given, on its own: say everything it needs.": "Instrukcja, którą każde uruchomienie dostaje samodzielnie: podaj wszystko, czego potrzebuje.", "The last %(n)s runs failed: %(why)s": "Ostatnie uruchomienia nie powiodły się (%(n)s): %(why)s", @@ -2153,6 +2256,7 @@ const LEMBAS_I18N = { "This file is too large to send.": "Ten plik jest za duży, aby go wysłać.", "This is a folder; attach the files in it.": "To jest folder; dołącz pliki, które zawiera.", "This is not a text file; it cannot be shown here.": "To nie jest plik tekstowy; nie można go tu pokazać.", + "This server cannot compact a chat from the app yet; the web interface can.": "Ten serwer nie umie jeszcze streścić czatu z aplikacji; interfejs WWW umie.", "This server has no scheduled tasks yet.": "Ten serwer nie ma jeszcze zaplanowanych zadań.", "Thought": "Rozumowanie", "Time": "Godzina", @@ -2162,6 +2266,7 @@ const LEMBAS_I18N = { "Tools": "Narzędzia", "Try again": "Spróbuj ponownie", "Type a command or a chat's title": "Wpisz polecenie lub tytuł czatu", + "Up to %(n)s at once": "Do %(n)s naraz", "Wait until the files are sent.": "Poczekaj, aż pliki zostaną wysłane.", "Waiting for a free model": "Czeka na wolny model", "Waiting for the browser…": "Czekam na przeglądarkę…", @@ -2210,10 +2315,11 @@ const LEMBAS_I18N = { }, "sk": { "%(model)s was busy, so it ran on this one.": "%(model)s bol zaneprázdnený, preto bežala na tomto.", - "%(n)s agents working": "Pracujúci agenti: %(n)s", "%(n)s finished": "Dokončené: %(n)s", "%(n)s missed": "zmeškané: %(n)s", "%(n)s queued": "V rade: %(n)s", + "%(n)s running": "Beží: %(n)s", + "%(n)s tasks": "Úlohy: %(n)s", "%(n)s tokens": "tokeny: %(n)s", "%(n)s tools offered.": "Ponúknuté nástroje: %(n)s.", "%(n)s waiting": "Čaká: %(n)s", @@ -2222,7 +2328,8 @@ const LEMBAS_I18N = { "%(percent)s%% used": "Využité: %(percent)s %%", "%(steps)s steps, %(tools)s tools": "Kroky: %(steps)s, nástroje: %(tools)s", "%(tokens)s tokens": "%(tokens)s tokenov", - "1 agent working": "1 agent pracuje", + "%(tokens)s until auto-compact": "%(tokens)s do automatického zhrnutia", + "1 task": "1 úloha", "A LLeMbas CLI service already runs here (pid %(pid)s), but is not connected: %(why)s": "Služba LLeMbas CLI tu už beží (pid %(pid)s), ale nie je pripojená: %(why)s", "A LLeMbas CLI service already runs here (pid %(pid)s); it is this computer's agent.": "Služba LLeMbas CLI tu už beží (pid %(pid)s); je agentom tohto počítača.", "A busy model is waited for, then the next free one is used.": "Na zaneprázdnený model sa čaká, potom sa použije ďalší voľný.", @@ -2235,8 +2342,6 @@ const LEMBAS_I18N = { "A scheduled task has a result.": "Naplánovaná úloha má výsledok.", "A shell as you, in one of these folders.": "Shell pod vaším účtom, v jednom z týchto priečinkov.", "A task without a model of its own runs on the first free one of these, in this order. None ticked: all of them.": "Úloha bez vlastného modelu beží na prvom voľnom z týchto, v tomto poradí. Žiadny nezaškrtnutý: všetky.", - "A team of up to %(n)s": "Tím: najviac %(n)s", - "A team works on it together, its own agent included.": "Pracuje na nej tím spoločne, vrátane jej vlastného agenta.", "About": "O aplikácii", "Account": "Účet", "Activity": "Aktivita", @@ -2245,7 +2350,6 @@ const LEMBAS_I18N = { "Agent": "Agent", "Agent chats can work in these folders and anything inside them — nowhere else on this computer.": "Agentské konverzácie môžu pracovať v týchto priečinkoch a vo všetkom, čo obsahujú — nikde inde na tomto počítači.", "Agent: %(why)s": "Agent: %(why)s", - "Agents": "Agenti", "Allow": "Povoliť", "Always": "Vždy", "Always allow": "Vždy povoliť", @@ -2256,7 +2360,9 @@ const LEMBAS_I18N = { "Archive chat": "Archivovať konverzáciu", "Attach files": "Prikladať súbory", "Auto — asks nothing": "Auto — na nič sa nepýta", + "Automatic compaction is off.": "Automatické zhrnutie je vypnuté.", "Back": "Späť", + "Background command": "Príkaz na pozadí", "Background tasks": "Úlohy na pozadí", "Cancel": "Zrušiť", "Carry it out": "Vykonať to", @@ -2269,9 +2375,14 @@ const LEMBAS_I18N = { "Close the activity panel": "Zavrieť panel aktivity", "Command": "Príkaz", "Commands": "Príkazy", + "Compact": "Zhrnúť", + "Compacting…": "Zhŕňa sa…", "Compaction buffer": "Rezerva na zhustenie", + "Compacts before the next reply.": "Zhrnie sa pred ďalšou odpoveďou.", + "Compacts by itself once the window is known.": "Zhrnie sa samo, keď bude okno známe.", "Connect": "Pripojiť", "Context": "Kontext", + "Context and background tasks": "Kontext a úlohy na pozadí", "Continue in a terminal": "Pokračovať v termináli", "Continue in a terminal…": "Pokračovať v termináli…", "Copied": "Skopírované", @@ -2297,22 +2408,24 @@ const LEMBAS_I18N = { "Edit message": "Upraviť správu", "Edit — asks before commands": "Edit — pýta sa pred príkazmi", "Empty folder": "Prázdny priečinok", + "Environment": "Prostredie", "Estimated: no reply has been counted yet.": "Odhad: žiadna odpoveď ešte nebola spočítaná.", "Every result, even with nothing to report.": "Každý výsledok, aj keď nie je čo hlásiť.", "Every weekday at 8:00, summarise the news on my reading list": "Každý pracovný deň o 8:00 zhrň správy z môjho zoznamu na čítanie", "Failed": "Zlyhalo", "Fewest": "Najmenej", "Files": "Súbory", + "Finished %(n)s": "Dokončené: %(n)s", "Folder": "Priečinok", "Free space": "Voľné miesto", "Hello": "Dobrý deň", "Hello, %(name)s": "Dobrý deň, %(name)s", "History": "História", + "How many work on it at once, the run's own agent among them, on the same model.": "Koľko na nej pracuje naraz, vrátane vlastného agenta behu, na rovnakom modeli.", "In your own words. The server reads them into a rule and an instruction, and shows you the next runs before anything is saved.": "Vlastnými slovami. Server z nich vytvorí pravidlo a pokyn a pred uložením vám ukáže ďalšie spustenia.", "Install LLeMbas %(version)s…": "Nainštalovať LLeMbas %(version)s…", "Instruction files": "Súbory s pokynmi", "It has not run yet.": "Ešte nebežal.", - "Its own agent included. Above one, it can add members that do the work while it leads them.": "Vrátane vlastného agenta. Pri viac ako jednom môže pridať členov, ktorí robia prácu, kým ich vedie.", "LLeMbas %(version)s is available (this is %(current)s)": "Je k dispozícii LLeMbas %(version)s (toto je %(current)s)", "LLeMbas Desktop needs a LLeMbas 2.0 server or later.": "LLeMbas Desktop potrebuje server LLeMbas 2.0 alebo novší.", "Last run": "Posledný beh", @@ -2351,7 +2464,7 @@ const LEMBAS_I18N = { "No model is available to this account.": "Tomuto účtu nie je dostupný žiadny model.", "No more runs": "Žiadne ďalšie spustenia", "No project folder yet: the agent can open nothing on this computer.": "Zatiaľ žiadny priečinok projektu: agent na tomto počítači nemôže nič otvoriť.", - "No team": "Bez tímu", + "None": "Žiadne", "Not measured.": "Nezmerané.", "Not run yet": "Ešte nebežala", "Not yet": "Ešte nie", @@ -2359,7 +2472,7 @@ const LEMBAS_I18N = { "Nothing is scheduled.": "Nič nie je naplánované.", "Nothing matches.": "Nič nezodpovedá.", "Nothing running.": "Nič nebeží.", - "Nothing runs in the background. Helpers, commands and a team's members show here while they work.": "Na pozadí nič nebeží. Pomocníci, príkazy a členovia tímu sa tu zobrazia, kým pracujú.", + "Nothing runs in the background. Subagents, a team's members and background commands show here while they work.": "Na pozadí nič nebeží. Subagenti, členovia tímu a príkazy na pozadí sa tu zobrazia, kým pracujú.", "Nothing to report": "Nič na hlásenie", "Nothing yet.": "Zatiaľ nič.", "Notifications": "Upozornenia", @@ -2430,9 +2543,13 @@ const LEMBAS_I18N = { "Stop %(name)s and the members under it? They leave the team.": "Zastaviť %(name)s a členov pod ním? Opustia tím.", "Stop the agent": "Zastaviť agenta", "Stopped.": "Zastavené.", + "Subagent": "Podagent", + "Subagents": "Podagenti", + "Summarise the earlier turns now and send the summary in their place.": "Zhrnúť skoršie kolá hneď a posielať namiesto nich zhrnutie.", "System prompt": "Systémový pokyn", "Taken in while it ran:": "Prevzaté počas behu:", - "Team: %(size)s of %(max)s agents": "Tím: %(size)s z %(max)s agentov", + "Team member": "Člen tímu", + "Team: %(size)s of at most %(max)s subagents": "Tím: %(size)s z najviac %(max)s subagentov", "Tell me": "Upozorniť ma", "Tell me when a reply or an agent's work is finished while I am elsewhere": "Upozorniť ma, keď je odpoveď alebo práca agenta hotová, kým som inde", "The agent asks to run %(tool)s:": "Agent žiada spustiť %(tool)s:", @@ -2449,6 +2566,7 @@ const LEMBAS_I18N = { "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does, and the same approval links this computer for the agent.": "Aplikácia sa na váš server prihlási raz, vo vašom prehliadači, ako každé zariadenie. Potom môže čítať a písať vaše konverzácie, ako webové rozhranie, a to isté schválenie prepojí tento počítač pre agenta.", "The app signs in to your server once, in your browser, as any device does. It may then read and write your chats, as the web interface does.": "Aplikácia sa na váš server prihlási raz, vo vašom prehliadači, ako každé zariadenie. Potom môže čítať a písať vaše konverzácie, ako webové rozhranie.", "The connection to the reply was lost: %(why)s": "Spojenie s odpoveďou sa prerušilo: %(why)s", + "The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.": "Najmenej a najviac subagentov, ktoré táto konverzácia spúšťa. Pracujú na rovnakom modeli, ak v konverzácii nepomenujete iný.", "The first free scheduling model": "Prvý voľný model na plánovanie", "The instruction each run is given, on its own: say everything it needs.": "Inštrukcia, ktorú dostane každé spustenie samostatne: uveďte všetko, čo potrebuje.", "The last %(n)s runs failed: %(why)s": "Posledné spustenia zlyhali (%(n)s): %(why)s", @@ -2467,6 +2585,7 @@ const LEMBAS_I18N = { "This file is too large to send.": "Tento súbor je príliš veľký na odoslanie.", "This is a folder; attach the files in it.": "Toto je priečinok; priložte súbory v ňom.", "This is not a text file; it cannot be shown here.": "Toto nie je textový súbor; nedá sa tu zobraziť.", + "This server cannot compact a chat from the app yet; the web interface can.": "Tento server zatiaľ nevie zhrnúť konverzáciu z aplikácie; webové rozhranie to vie.", "This server has no scheduled tasks yet.": "Tento server zatiaľ nemá naplánované úlohy.", "Thought": "Premýšľal", "Time": "Čas", @@ -2476,6 +2595,7 @@ const LEMBAS_I18N = { "Tools": "Nástroje", "Try again": "Skúsiť znova", "Type a command or a chat's title": "Napíšte príkaz alebo názov konverzácie", + "Up to %(n)s at once": "Najviac %(n)s naraz", "Wait until the files are sent.": "Počkajte, kým sa súbory odošlú.", "Waiting for a free model": "Čaká na voľný model", "Waiting for the browser…": "Čaká sa na prehliadač…", diff --git a/ui/js/activity.js b/ui/js/activity.js index 7a1d9a0..f49c181 100644 --- a/ui/js/activity.js +++ b/ui/js/activity.js @@ -1,14 +1,18 @@ -// The chat's activity panel, beside it: what is in its context, by category, against the model's -// window; the files the chat and its agents wrote; every background agent -- a team's members as -// a tree, helpers and commands -- with its state, how long it has run, its model, its latest step -// and what it is writing, its whole conversation read-only and a button to stop it; the team's -// room; and the plan. The strip above the message box sums the agents up and opens it. The same -// facts as the server's own panel (`services/activity.py`), from /api/v2: +// The chat's activity panel, beside it, opened from the header's button at any time: where an +// agent chat works; what is in its context, by category, against the model's window, how far it +// is to the automatic compaction and a button to compact now; the files the chat and its +// subagents wrote; every background task -- subagents, a team's members as a tree under the one +// that leads them, background commands -- with how long it has run and a stop square, unfolding +// to its latest step, what it is writing and its whole conversation, read-only; the finished ones +// folded; the team's room; and the plan. The line above the message box sums up what runs, while +// anything does, and opens it. The same facts as the server's own panel (`services/activity.py`), +// from /api/v2: // // GET /chats/{chat}/activity?since=&context= everything, with a `version` // GET /chats/{chat}/activity/events `activity` {version, summary} on each change -// GET /chats/{chat}/agents/{kind}/{id} one agent and its conversation +// GET /chats/{chat}/agents/{kind}/{id} one task and its conversation // POST /chats/{chat}/agents/{kind}/{id}/stop +// POST /chats/{chat}/compact summarise the earlier turns now // // The events stream is followed for as long as a chat is open: it keeps the strip current, and // while the panel is open a new `version` reads the panel again. The context is the costly part @@ -31,6 +35,8 @@ const SHOWN = 6 const CONTEXT_EVERY = 15000 let layout = () => {} // (on) -> the shell makes room for the panel +let onThisComputer = () => false // (chat) -> whether an agent chat works on this computer +let onCompacted = () => {} // (chat id) -> the conversation is read again let chat = null // the open chat: { id, kind, … } let stream = null // the events stream's handle let retry = 0 // the reconnect timer @@ -69,12 +75,14 @@ export function compact(value) { return `${trim(n / 1000000, 2)}M` } -/** "3 agents working · 1 queued · 2 finished", or "" for none (the server's `summary_text`). */ +/** + * "3 running · 1 queued · 2 finished", or "" for none: every background task -- a subagent, a + * team's member, a command -- counts the same, as the panel lists them together. + */ export function summaryText(counts) { if (!counts) return "" const parts = [] - if (counts.working === 1) parts.push(t("1 agent working")) - else if (counts.working) parts.push(t("%(n)s agents working", { n: counts.working })) + if (counts.working) parts.push(t("%(n)s running", { n: counts.working })) if (counts.queued) parts.push(t("%(n)s queued", { n: counts.queued })) if (counts.waiting) parts.push(t("%(n)s waiting", { n: counts.waiting })) if (counts.finished) parts.push(t("%(n)s finished", { n: counts.finished })) @@ -141,9 +149,10 @@ export function watchActivity(next) { cursor = 0 readAt = contextAt = 0 view = null + compactError = "" openRows.clear() renderStrip() - $("activity-open")?.setAttribute("aria-expanded", String(panelOpen())) + markOpen() if (!chat) { if (panelOpen()) showPanel(false) return @@ -269,36 +278,58 @@ async function read(withContext) { } } -// --- The strip above the message box --------------------------------------------------------------- +// --- The line above the message box, and the header's button --------------------------------------- + +/** Both ways into the panel say whether it is open. */ +function markOpen() { + for (const id of ["activity-open", "activity-strip-btn"]) $(id)?.setAttribute("aria-expanded", String(panelOpen())) +} function renderStrip() { const strip = $("activity-strip") - // A chip for every open chat: what runs, while something does, as the server's strip says it (a - // chat whose helpers all finished long ago does not carry "12 finished" for ever: the panel - // still lists them); else only the way into the panel. - strip.hidden = !chat - if (!chat) return clear(strip) - const active = summary?.active ? summaryText(summary) : "" - const text = active || t("Activity") + // Only while something runs, as the server's own line: the header's button is the way into the + // panel at any other time (and a chat whose tasks all finished long ago does not carry + // "12 finished" for ever: the panel still lists them). + const active = chat && summary?.active ? summaryText(summary) : "" + strip.hidden = !active + if (!active) return clear(strip) strip.replaceChildren( h( "button", { type: "button", - id: "activity-open", - class: `strip__btn${active ? " is-active" : ""}`, - "aria-label": `${text} — ${panelOpen() ? t("Close the activity panel") : t("Open the activity panel")}`, + id: "activity-strip-btn", + class: "strip__btn is-active", + "aria-label": `${active} — ${panelOpen() ? t("Close the activity panel") : t("Open the activity panel")}`, "aria-controls": "activity", "aria-expanded": String(panelOpen()), onclick: togglePanel, }, h("span", { class: "dot", "aria-hidden": "true" }), - h("span", { class: "strip__text", text }), + h("span", { class: "strip__text", text: active }), icon(ICONS.chevron), ), ) } +/** The header's button: the panel, open or closed, for every open chat. */ +export function activityButton() { + return h( + "button", + { + type: "button", + class: "tool", + id: "activity-open", + "aria-label": t("Context and background tasks"), + title: t("Context and background tasks"), + "aria-controls": "activity", + "aria-expanded": String(panelOpen()), + onclick: togglePanel, + }, + icon(ICONS.tasks), + ) +} + // --- The panel ------------------------------------------------------------------------------------------ /** Open or close the panel (the header's Activity button, the strip, Escape). */ @@ -306,14 +337,16 @@ export function showPanel(on) { if (on && !chat) return $("activity").hidden = !on layout(on) - $("activity-open")?.setAttribute("aria-expanded", String(on)) + markOpen() clearInterval(ticker) ticker = 0 if (!on) { view = null + renderStrip() return } ticker = setInterval(tick, 1000) + renderStrip() render() read(true) $("activity-close").focus() @@ -359,15 +392,43 @@ function render() { } // Kept where the reader was: the panel is drawn again on every change. const scroll = body.scrollTop - body.replaceChildren( + const entries = data.agents || [] + const parts = [ + chat?.kind === "agent" && chat.device ? section("environment", t("Environment"), 0, environmentPart(chat)) : null, section("context", t("Context"), 0, contextPart(data.context)), section("outputs", t("Outputs"), (data.outputs || []).length, outputsPart(data.outputs || [])), - section("tasks", t("Background tasks"), 0, tasksPart()), + section("tasks", t("Background tasks"), 0, tasksPart(entries)), + data.team ? section("room", t("Room"), room.length, roomPart()) : null, data.plan ? section("plan", t("Plan"), 0, h("div", { class: "activity__plan" }, planList(data.plan))) : null, - ) + ] + body.replaceChildren(...parts.filter(Boolean)) body.scrollTop = scroll } +/** How many tasks, nested ones included: those still at work, or those finished. */ +function count(list, active) { + let n = 0 + for (const a of list) { + if (ACTIVE.includes(a.state) === active) n += 1 + n += count(a.children || [], active) + } + return n +} + +/** Where an agent chat works: its folder, on this computer or another device. */ +function environmentPart(c) { + const dir = c.device?.directory || "" + const name = dir.split(/[\\/]/).filter(Boolean).pop() || dir + const here = onThisComputer(c) + return h( + "p", + { class: "env", title: dir }, + icon(ICONS.folder), + h("bdi", { class: "env__name", text: name }), + h("span", { class: "env__where", text: here ? t("This computer") : t("Another device") }), + ) +} + function contextPart(c) { if (!c) return h("p", { class: "activity__empty", text: t("Not measured.") }) const known = c.percent !== null && c.percent !== undefined @@ -410,7 +471,62 @@ function contextPart(c) { { class: "ctx__note" }, `${c.measured ? t("Counted by the model at the last reply; the categories are estimated.") : t("Estimated: no reply has been counted yet.")} ${t("%(n)s tools offered.", { n: c.tools_count ?? 0 })}`, ) - return h("div", { class: "ctx" }, used, bar, rows, note) + return h("div", { class: "ctx" }, used, bar, rows, compactRow(c), note) +} + +/** + * How far it is to the automatic compaction -- the server compacts before a turn once the context + * would reach `threshold` % of the window; 0 is off -- and the button that compacts now. + */ +function compactRow(c) { + const limit = Number(c.limit) || 0 + const threshold = Number(c.threshold) + let words + if (!(threshold > 0)) words = t("Automatic compaction is off.") + else if (!limit || threshold >= 100) words = t("Compacts by itself once the window is known.") + else { + const until = Math.floor((limit * threshold) / 100) - (Number(c.used) || 0) + words = until > 0 ? t("%(tokens)s until auto-compact", { tokens: compact(until) }) : t("Compacts before the next reply.") + } + const busy = compacting === chat?.id + return h( + "div", + { class: "ctx__compact" }, + h("span", { class: "ctx__until", text: words }), + h("button", { + type: "button", + class: "btn btn--sm", + text: busy ? t("Compacting…") : t("Compact"), + disabled: busy, + title: t("Summarise the earlier turns now and send the summary in their place."), + onclick: compactNow, + }), + compactError ? h("p", { class: "ctx__error", role: "alert", text: compactError }) : null, + ) +} + +let compacting = null // the chat being compacted +let compactError = "" + +async function compactNow() { + if (!chat || compacting) return + const id = chat.id + compacting = id + compactError = "" + render() + try { + await post(`/chats/${enc(id)}/compact`) + compacting = null + if (chat?.id !== id) return + onCompacted(id) + read(true) + } catch (err) { + compacting = null + if (chat?.id !== id) return + // A server without the route in its /api/v2 says 404 or 405: said as what it means. + compactError = err?.status === 404 || err?.status === 405 ? t("This server cannot compact a chat from the app yet; the web interface can.") : why(err) + render() + } } /** A category's key as a class name: the server's words, kept to letters and underscores. */ @@ -439,64 +555,71 @@ function outputsPart(outputs) { ) } -function tasksPart() { - const entries = data.agents || [] +function tasksPart(entries) { const team = data.team const box = h("div", { class: "tasks", "aria-live": "polite" }) if (!entries.length && !team) { - box.append(h("p", { class: "activity__empty", text: t("Nothing runs in the background. Helpers, commands and a team's members show here while they work.") })) + box.append(h("p", { class: "activity__empty", text: t("Nothing runs in the background. Subagents, a team's members and background commands show here while they work.") })) return box } - box.append(h("p", { class: "tasks__summary", text: summaryText(data.summary) || t("Nothing running.") })) if (team) { - box.append(h("p", { class: "tasks__team", text: t("Team: %(size)s of %(max)s agents", { size: team.size, max: team.max }) })) + box.append(h("p", { class: "tasks__team", text: t("Team: %(size)s of at most %(max)s subagents", { size: team.size, max: team.max }) })) if (team.goal) box.append(h("p", { class: "tasks__goal", text: team.goal })) } - const live = entries.filter((e) => ACTIVE.includes(e.state)) - const ended = entries.filter((e) => !ACTIVE.includes(e.state)) + // At the top level, what still runs -- with its own tasks under it, finished or not -- and then + // what finished with nothing under it still at work, folded. + const live = entries.filter((e) => ACTIVE.includes(e.state) || count(e.children || [], true)) + const ended = entries.filter((e) => !live.includes(e)) + box.append(h("p", { class: "tasks__group" }, h("span", { text: t("Running") }), h("span", { class: "activity__count", text: String(count(entries, true)) }))) if (live.length) { box.append(h("div", { class: "tasks__list" }, live.slice(0, SHOWN).map(agentRows))) if (live.length > SHOWN) box.append(fold("more", t("Show %(n)s more", { n: live.length - SHOWN }), live.slice(SHOWN))) - } - if (ended.length) box.append(fold("finished", t("%(n)s finished", { n: ended.length }), ended)) - if (team) { - box.append(h("h3", { class: "activity__subheading", text: t("Room") })) - box.append( - room.length - ? h( - "ol", - { class: "room" }, - room.map((m) => - h( - "li", - { class: `room__entry${m.report ? " is-report" : ""}` }, - h( - "div", - { class: "room__meta" }, - h("span", { class: "room__n", text: `#${m.n}` }), - h("span", { class: "room__route", text: `${m.from} → ${(m.to || []).join(", ")}` }), - m.report ? h("span", { class: "chip room__badge", text: t("report") }) : null, - ), - h("div", { class: "room__text md" }, markdown(String(m.text || ""))), - ), - ), - ) - : h("p", { class: "activity__empty", text: t("Nothing has been said in the room yet.") }), - ) - } + } else box.append(h("p", { class: "activity__empty", text: t("Nothing running.") })) + if (ended.length) box.append(fold("finished", t("Finished %(n)s", { n: count(ended, false) }), ended, "tasks__finished")) return box } -/** A folded list of agents ("Show 3 more", "12 finished"), remembered open across redraws. */ -function fold(name, label, list) { - const el = h("details", { class: "tasks__more", open: openRows.has(`fold:${name}`) }, h("summary", { text: label }), h("div", { class: "tasks__list" }, list.map(agentRows))) +function roomPart() { + if (!room.length) return h("p", { class: "activity__empty", text: t("Nothing has been said in the room yet.") }) + return h( + "ol", + { class: "room" }, + room.map((m) => + h( + "li", + { class: `room__entry${m.report ? " is-report" : ""}` }, + h( + "div", + { class: "room__meta" }, + h("span", { class: "room__n", text: `#${m.n}` }), + h("span", { class: "room__route", text: `${m.from} → ${(m.to || []).join(", ")}` }), + m.report ? h("span", { class: "chip room__badge", text: t("report") }) : null, + ), + h("div", { class: "room__text md" }, markdown(String(m.text || ""))), + ), + ), + ) +} + +/** A folded list of tasks ("Show 3 more", "Finished 12", "2 tasks"), remembered across redraws. */ +function fold(name, label, list, cls = "") { + const el = h( + "details", + { class: `tasks__more ${cls}`, open: openRows.has(`fold:${name}`) }, + h("summary", null, h("span", { class: "tasks__chev", "aria-hidden": "true" }, icon(ICONS.chevron)), h("span", { text: label })), + h("div", { class: "tasks__list" }, list.map(agentRows)), + ) el.addEventListener("toggle", () => (el.open ? openRows.add(`fold:${name}`) : openRows.delete(`fold:${name}`))) return el } -/** An agent and, under it, the agents it leads or started. */ +/** A task and, folded under it, the tasks it leads or started ("1 task", "3 tasks"). */ function agentRows(a) { - return [agentRow(a), ...(a.children || []).map(agentRows)] + const kids = a.children || [] + if (!kids.length) return agentRow(a) + const nested = fold(`under:${a.kind}:${a.id}`, kids.length === 1 ? t("1 task") : t("%(n)s tasks", { n: kids.length }), kids, "tasks__nested") + nested.style.setProperty("--depth", String(Math.max(0, Math.min(6, (Number(a.depth) || 0) + 1)))) + return [agentRow(a), nested] } function agentRow(a) { @@ -512,7 +635,7 @@ function agentRow(a) { "button", { type: "button", - class: "pane__btn agent__stop", + class: "agent__stop", "aria-label": t("Stop %(name)s", { name: a.name }), title: t("Stop %(name)s", { name: a.name }), onclick: (e) => { @@ -521,13 +644,15 @@ function agentRow(a) { stopAgent(a) }, }, - icon(ICONS.stop), + h("span", { class: "agent__square", "aria-hidden": "true" }), ) - : h("span", { class: "agent__stop", "aria-hidden": "true" }) + : h("span", { class: "agent__stop is-none", "aria-hidden": "true" }) const facts = h( "p", { class: "agent__facts" }, h("span", { class: "agent__state", text: stateWord(a.state) }), + h("span", { text: kindWord(a) }), + a.kind !== "member" && a.role ? h("code", { class: "agent__id", text: a.name || a.id }) : null, a.agent ? h("span", { text: a.agent }) : null, a.model ? h("span", { class: "agent__model", text: a.model }) : null, a.steps ? h("span", { text: t("%(steps)s steps, %(tools)s tools", { steps: a.steps, tools: a.tools }) }) : null, @@ -547,8 +672,8 @@ function agentRow(a) { h( "summary", { class: "agent__row" }, - h("span", { class: "agent__dot", "aria-hidden": "true" }), - h("span", { class: "agent__what" }, h("span", { class: "agent__name", text: a.name || a.id }), a.role ? h("span", { class: "agent__role", text: a.role }) : null), + h("span", { class: "agent__chev", "aria-hidden": "true" }, icon(ICONS.chevron)), + h("span", { class: "agent__what", title: label(a) }, h("bdi", { class: "agent__name", text: label(a) })), time, stopBtn, ), @@ -556,12 +681,11 @@ function agentRow(a) { "div", { class: "agent__body" }, facts, + a.kind === "member" && a.role ? h("p", { class: "agent__role", text: a.role }) : null, a.brief ? h("p", { class: "agent__brief", text: a.brief }) : null, step, a.text ? h("p", { class: "agent__text", text: a.text }) : null, - a.transcript - ? h("button", { type: "button", class: "btn btn--sm", text: t("Open its conversation"), onclick: () => openAgent(a) }) - : null, + a.transcript ? h("button", { type: "button", class: "btn btn--sm", text: t("Open its conversation"), onclick: () => openAgent(a) }) : null, ), ) el.style.setProperty("--depth", String(Math.max(0, Math.min(6, Number(a.depth) || 0)))) @@ -569,6 +693,22 @@ function agentRow(a) { return el } +/** + * A task's line: a team's member by its name (it is how the room and the others call it); a + * subagent or a command by what it was given to do, its id only where there is nothing else. + */ +function label(a) { + if (a.kind === "member") return a.name || a.id + return a.role || a.brief || a.name || a.id +} + +/** What a task is: a team's member, a subagent, or a background command. */ +function kindWord(a) { + if (a.kind === "member") return t("Team member") + if (a.type === "command") return t("Background command") + return t("Subagent") +} + async function stopAgent(a) { if (!chat) return if (a.kind === "member") { @@ -667,8 +807,10 @@ async function readAgent() { // --- Start ------------------------------------------------------------------------------------------ -export function initActivity({ onLayout }) { +export function initActivity({ onLayout, here, compacted }) { layout = onLayout || layout + onThisComputer = here || onThisComputer + onCompacted = compacted || onCompacted $("activity-close").replaceChildren(icon(ICONS.close)) $("activity-close").addEventListener("click", () => showPanel(false)) $("activity-back").replaceChildren(icon(ICONS.back)) diff --git a/ui/js/chat.js b/ui/js/chat.js index 1e2e45f..bb5bd5f 100644 --- a/ui/js/chat.js +++ b/ui/js/chat.js @@ -13,9 +13,9 @@ import { markdown } from "./markdown.js" import { openViewer, showKind } from "./viewer.js" import { readLocal } from "./explorer.js" import { menu, ask, showLine, popover, closePopover } from "./popup.js" -import { avatar, agentsControl, teamPossible, levelsOf, levelWord, picture } from "./models.js" +import { avatar, agentsControl, teamPossible, subagentsCap, SUBAGENTS_HINT, levelsOf, levelWord, picture } from "./models.js" import { readyIds, sending, sent, discard } from "./attach.js" -import { watchActivity, activityChanged, planList } from "./activity.js" +import { watchActivity, activityChanged, planList, activityButton } from "./activity.js" import { agentBlock, agentReady, agentState, onAgentChange } from "./agent.js" import { folderName } from "./list.js" @@ -30,7 +30,7 @@ export function openChatId() { // --- Reading ----------------------------------------------------------------------------------- -function onThisComputer(chat) { +export function onThisComputer(chat) { return !!chat?.device && ctx.thisDevices().includes(chat.device.token_id) } @@ -552,6 +552,7 @@ function renderHead(chat) { ) } } + tools.append(activityButton()) tools.append(h("button", { type: "button", class: "tool", "aria-label": t("More"), title: t("More"), onclick: (e) => chatMenu(e.currentTarget, open?.chat || chat) }, icon(ICONS.more))) } @@ -564,13 +565,20 @@ async function chatModels(chat) { } } -/** Whether this chat may have a team (`GET /chats/{chat}/team`): only a chat on the server. */ +/** + * Whether this chat is offered subagents, and the instance's most: the chat's own word where the + * server gives one (`subagents` on the chat), else its team's (`GET /chats/{chat}/team`) -- only a + * chat on the server. null where it is not offered. + */ async function teamOffered(chat) { - if (chat.kind !== "chat") return false + const said = chat.subagents + if (said !== undefined && said !== null) return (typeof said === "object" ? said.offered : said) ? { cap: subagentsCap(said, ctx.me()) } : null + if (chat.kind !== "chat") return null try { - return !!(await get(`/chats/${encodeURIComponent(chat.id)}/team`)).team?.offered + const team = (await get(`/chats/${encodeURIComponent(chat.id)}/team`)).team + return team?.offered ? { cap: subagentsCap(team, ctx.me()) } : null } catch { - return false + return null } } @@ -640,26 +648,31 @@ function effortChip(model, value, onChange) { }) } -/** The team's size: a chip saying it, opening the two fields. `value` { min, max } or empty. */ -function agentsChip(value, onChange) { +/** + * The subagents a chat may run: a chip saying the fewest and the most, opening the two fields. + * `value` { min, max } or empty; `cap` the instance's most, where the server says it. + */ +function agentsChip(value, onChange, cap) { const said = value?.min || value?.max ? `${value.min ?? "…"}–${value.max ?? "…"}` : t("default") return chip({ ico: ICONS.users, - label: `${t("Agents")} ${said}`, - title: t("Its own agent included. Above one, it can add members that do the work while it leads them."), + label: `${t("Subagents")} ${said}`, + title: SUBAGENTS_HINT(), + cls: "cchip--subagents", onclick: (e) => { - const fields = agentsControl({ value, id: "agents-min" }) + const fields = agentsControl({ value, id: "agents-min", cap }) popover( e.currentTarget, h( "div", { class: "pop__body" }, - h("label", { class: "pop__title", for: "agents-min", text: t("Agents") }), + h("label", { class: "pop__title", for: "agents-min", text: t("Subagents") }), + h("div", { class: "agents__heads", "aria-hidden": "true" }, h("span", { text: t("Fewest") }), h("span"), h("span", { text: t("Most") })), fields, - h("p", { class: "hint", text: t("Its own agent included. Above one, it can add members that do the work while it leads them.") }), + h("p", { class: "hint", text: SUBAGENTS_HINT() }), h("div", { class: "pop__actions" }, h("button", { type: "button", class: "btn btn--sm btn--primary", text: t("Save"), onclick: () => (closePopover(), onChange(fields.value)) })), ), - { up: true, label: t("Agents") }, + { up: true, label: t("Subagents") }, ) }, }) @@ -705,7 +718,7 @@ async function renderChips() { renderChips() }, mayPick)) if (model) parts.push(effortChip(model, draft.effort, (l) => ((draft.effort = l), renderChips()))) - if (draft.kind === "chat" && teamPossible(model)) parts.push(agentsChip(draft.agents, (a) => ((draft.agents = a), renderChips()))) + if (draft.kind === "chat" && teamPossible(model)) parts.push(agentsChip(draft.agents, (a) => ((draft.agents = a), renderChips()), subagentsCap(model?.subagents, ctx.me()))) box.replaceChildren(...parts.filter(Boolean)) return } @@ -732,8 +745,9 @@ async function renderChips() { if (chat.model) parts.push(modelChip(models, chat.model, (id) => save({ model: id }), mayPick)) parts.push(effortChip(current, chat.effort || levelsOf(current).start, (l) => save({ effort: l }))) box.replaceChildren(...parts.filter(Boolean)) - if (!(await teamOffered(chat)) || drawing !== chipsDrawn || open?.chat?.id !== chat.id) return - box.append(agentsChip(open.chat.agents || chat.agents, (a) => save({ agents: a }))) + const offer = await teamOffered(chat) + if (!offer || drawing !== chipsDrawn || open?.chat?.id !== chat.id) return + box.append(agentsChip(open.chat.agents || chat.agents, (a) => save({ agents: a }), offer.cap)) } /** diff --git a/ui/js/dom.js b/ui/js/dom.js index e1a489f..c0aa3c8 100644 --- a/ui/js/dom.js +++ b/ui/js/dom.js @@ -81,6 +81,7 @@ export const ICONS = { attach: "M7.25 2.5h1.5v4.75h4.75v1.5H8.75v4.75h-1.5V8.75H2.5v-1.5h4.75z", bolt: "M9.5 1L3 9.25h4.25L6.5 15 13 6.75H8.75z", stop: "M4.5 4.5h7v7h-7z", + tasks: "M2 3.25h2v2H2zM5.5 3.5H14V5H5.5zM2 7h2v2H2zM5.5 7.25H14v1.5H5.5zM2 10.75h2v2H2zM5.5 11H14v1.5H5.5z", back: "M10 3.5L5.5 8 10 12.5 11.1 11.4 7.7 8 11.1 4.6z", terminal: "M1.5 2.5h13v11h-13zM3 4v8h10V4zM4.2 5.4l2.6 2.6-2.6 2.6-1-1L4.8 8 3.2 6.4zM7.5 10h4v1.5h-4z", search: "M7 2a5 5 0 013.95 8.07l3.24 3.24-1.06 1.06-3.24-3.24A5 5 0 117 2zm0 1.5a3.5 3.5 0 100 7 3.5 3.5 0 000-7z", diff --git a/ui/js/main.js b/ui/js/main.js index b336f23..b3549fc 100644 --- a/ui/js/main.js +++ b/ui/js/main.js @@ -12,7 +12,7 @@ import { renderSettings, initSettings, scrollToSection } from "./settings.js" import { initViewer, onViewer, closeViewer } from "./viewer.js" import { initExplorer, showLocal, showFilesTab } from "./explorer.js" import { initList, refreshList, markCurrent } from "./list.js" -import { initChat, openChat, newChat, closeChat, openChatId, chatMenu, statusChanged, draftKind } from "./chat.js" +import { initChat, openChat, newChat, closeChat, openChatId, chatMenu, statusChanged, draftKind, onThisComputer } from "./chat.js" import { initAttach, allowAttach } from "./attach.js" import { initPalette, openPalette } from "./palette.js" import { initActivity, showPanel, togglePanel, panelOpen } from "./activity.js" @@ -282,6 +282,9 @@ async function boot() { onLayout: (on) => { $("shell").dataset.activity = String(on) }, + here: onThisComputer, + // The conversation as it now stands: the summary's divider, read again, if it is still open. + compacted: (id) => openChatId() === id && openChat(id), }) $("new-chat-btn").prepend(icon(ICONS.plus)) diff --git a/ui/js/models.js b/ui/js/models.js index a151d3d..7bff80c 100644 --- a/ui/js/models.js +++ b/ui/js/models.js @@ -123,7 +123,7 @@ export function modelPicker({ id, models, value, onChange, label }) { return btn } -// --- How hard a model thinks, and how many agents a chat may have -------------------------------- +// --- How hard a model thinks, and how many subagents a chat may have -------------------------------- // // The levels are the harness spec's (3.2.0, `models/schema.json`), as /api/v2/models gives them: // `levels` in offering order (`off` first where the model can switch thinking off, then its @@ -193,28 +193,45 @@ export function effortControl({ model, value, onChange, id, compact }) { } /** - * Whether a new chat on `model` may have a team: a chat on the server (an agent chat's team runs - * on its device), a model that calls tools and serves two requests at once (`parallel` null is a - * hosted API with no stated limit). The server decides again; this only keeps the fields away - * where they could never apply. An open chat asks the server (`GET /chats/{chat}/team`). + * Whether a new chat on `model` is offered subagents. The server says so where it can: a model's + * `subagents` in `/models` (a flag, or `{offered}`), true when subagents are on for the model and + * the instance and at least one model could serve as one -- the model itself with room for two + * requests at once, or a usable model outside its one-model-at-a-time server. A server that does + * not say it yet: a model that calls tools and serves two requests at once (`parallel` null is a + * hosted API with no stated limit). The server decides again; this only keeps the chip away where + * it could never apply. An open chat asks the server (`GET /chats/{chat}/team`). */ export function teamPossible(model) { + const said = model?.subagents + if (said !== undefined && said !== null) return typeof said === "object" ? !!said.offered : !!said return !!model?.tools && (model.parallel === null || model.parallel === undefined || model.parallel >= 2) } +/** The most subagents the instance allows a chat (`cap`), where the server says it; else 32. */ +export const SUBAGENTS_CAP = 32 +export const SUBAGENTS_HINT = () => t("The fewest and the most subagents this chat runs. They work on the same model unless you name another one in the chat.") +export function subagentsCap(...sources) { + for (const s of sources) { + const n = Number(s?.cap ?? s?.subagents_cap ?? s?.subagents?.cap) + if (Number.isFinite(n) && n >= 1) return n + } + return SUBAGENTS_CAP +} + /** - * The team's size: the fewest and the most agents, the chat's own agent included, as two number - * fields on one shared track. `value` is { min, max } (empty fields for a new chat: the person's - * default for new chats then stands); `onChange({ min, max })` once a field is changed, with the - * empty one left out. The server checks the pair and says the bounds when it refuses one. + * The subagents a chat may run: the fewest and the most, as two number fields on one shared + * track. `value` is { min, max } (empty fields for a new chat: the server's defaults then stand); + * `cap` the instance's most; `onChange({ min, max })` once a field is changed, with the empty one + * left out. The server checks the pair and says the bounds when it refuses one. */ -export function agentsControl({ value, onChange, id, compact }) { +export function agentsControl({ value, onChange, id, compact, cap = SUBAGENTS_CAP }) { const field = (which, v, label) => h("input", { type: "number", class: "agents__input", id: which === "min" ? id : null, min: "1", + max: String(cap), step: "1", inputmode: "numeric", value: v === undefined || v === null ? "" : String(v), @@ -226,8 +243,7 @@ export function agentsControl({ value, onChange, id, compact }) { const high = field("max", value?.max, t("Most")) const bounds = () => { high.min = low.value || "1" - if (high.value) low.max = high.value - else low.removeAttribute("max") + low.max = high.value || String(cap) } bounds() const read = () => { @@ -244,8 +260,8 @@ export function agentsControl({ value, onChange, id, compact }) { } const el = h( "span", - { class: `agents${compact ? " agents--compact" : ""}`, role: "group", "aria-label": t("Agents"), title: t("Its own agent included. Above one, it can add members that do the work while it leads them.") }, - compact ? h("span", { class: "agents__label", text: t("Agents") }) : null, + { class: `agents${compact ? " agents--compact" : ""}`, role: "group", "aria-label": t("Subagents"), title: SUBAGENTS_HINT() }, + compact ? h("span", { class: "agents__label", text: t("Subagents") }) : null, low, h("span", { class: "agents__dash", "aria-hidden": "true", text: "–" }), high, diff --git a/ui/js/scheduled.js b/ui/js/scheduled.js index eb090c6..f58f098 100644 --- a/ui/js/scheduled.js +++ b/ui/js/scheduled.js @@ -341,7 +341,7 @@ async function drawTask(id) { fact(t("Last run"), statusChip(task.last_run, task.running)), fact(t("Model"), modelWords(models, task.model)), fact(t("Reasoning effort"), h("span", { text: task.effort ? levelWord(task.effort) : t("The model's own") })), - fact(t("Agents"), h("span", { text: task.agents ? t("A team of up to %(n)s", { n: task.agents }) : t("No team") })), + fact(t("Subagents"), h("span", { text: task.agents ? t("Up to %(n)s at once", { n: task.agents }) : t("None") })), fact(t("Tell me"), h("span", { text: NOTIFY[task.notify]?.() || NOTIFY.matters() })), fact(t("Runs"), h("span", { text: MODE[task.mode]?.() || MODE.fresh() })), ), @@ -582,15 +582,15 @@ async function drawForm(task) { const agents = h( "select", { id: "sched-agents", onchange: (e) => (draft.agents = Number(e.target.value) || null) }, - h("option", { value: "", text: t("No team"), selected: !draft.agents }), - Array.from({ length: MAX_AGENTS - 1 }, (_, i) => i + 2).map((n) => h("option", { value: String(n), text: t("A team of up to %(n)s", { n }), selected: draft.agents === n })), + h("option", { value: "", text: t("None"), selected: !draft.agents }), + Array.from({ length: MAX_AGENTS - 1 }, (_, i) => i + 2).map((n) => h("option", { value: String(n), text: t("Up to %(n)s at once", { n }), selected: draft.agents === n })), ) settings.replaceChildren( field(t("Tell me"), select("sched-notify", NOTIFY, "notify", () => (settings.querySelector("#sched-notify-hint").textContent = NOTIFY_HINT[draft.notify]())), NOTIFY_HINT[draft.notify]?.() || "", "sched-notify", "sched-notify-hint"), field(t("Runs"), select("sched-mode", MODE, "mode"), draft.mode === "continue" ? t("Each run sees the ones before it.") : t("Each run starts with nothing but the instruction."), "sched-mode"), field(t("Model"), modelSelect, t("A busy model is waited for, then the next free one is used."), "sched-model"), field(t("Reasoning effort"), effort, levels.length ? "" : t("Choose a model to choose its effort."), "sched-effort"), - field(t("Agents"), agents, t("A team works on it together, its own agent included."), "sched-agents"), + field(t("Subagents"), agents, t("How many work on it at once, the run's own agent among them, on the same model."), "sched-agents"), ) settings.querySelector("#sched-mode").addEventListener("change", drawSettings) }