feat: import agents_and_robots platform as unibots (Matrix-out, unibus transport)
Reemplaza el scaffold del echobot por la plataforma completa de bots traida desde ~/DataProyects/Github/agents_and_robots tras la operacion Matrix-out: los bots ya no hablan por Matrix sino por el bus unibus (modelo todo-rooms + E2E via shell/transportunibus sobre github.com/enmanuel/unibus/pkg/client). - go.mod: replace de unibus -> ../unibus y de fn-registry -> ../../../.. (paths relativos reajustados a la nueva ubicacion dentro de fn_registry). - app.md: bump a 0.2.0, descripcion + arquitectura + comandos + gotchas reales. - modulo Go conservado como github.com/enmanuel/agents (sin reescribir imports). agents_and_robots queda archivado como museo de la era Matrix.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import { test, expect, handleElementDialogs } from "../fixtures/persistent-context";
|
||||
import {
|
||||
goToRoom,
|
||||
sendMessage,
|
||||
waitForBotReply,
|
||||
assertNoDecryptionErrors,
|
||||
startThreadOnLastMessage,
|
||||
waitForThreadReplyViaSdk,
|
||||
closeThreadPanel,
|
||||
} from "../fixtures/matrix-room";
|
||||
|
||||
test.describe("asistente-2", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await handleElementDialogs(page);
|
||||
await goToRoom(page, "Asistente 2");
|
||||
// Cerrar thread panel si estaba abierto de sesiones previas.
|
||||
// Si queda abierto, sus sender elements contaminan los locators de waitForBotReply.
|
||||
await closeThreadPanel(page);
|
||||
});
|
||||
|
||||
test("responde a un saludo", async ({ page }) => {
|
||||
await sendMessage(page, "Hola, que tal?");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Asistente 2",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
expect(reply.length).toBeGreaterThan(10);
|
||||
});
|
||||
|
||||
test("!tools muestra herramientas disponibles", async ({ page }) => {
|
||||
await sendMessage(page, "!tools");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 10_000,
|
||||
sender: "Asistente 2",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
// asistente-2 tiene al menos current_time
|
||||
expect(reply.toLowerCase()).toMatch(/current_time|hora|herramienta|tool/);
|
||||
});
|
||||
|
||||
test("pregunta que activa tool use (que hora es?)", async ({ page }) => {
|
||||
await sendMessage(page, "Que hora es ahora mismo?");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Asistente 2",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
// La respuesta debe contener algo relacionado con tiempo/hora
|
||||
expect(reply.length).toBeGreaterThan(5);
|
||||
});
|
||||
|
||||
test("!help muestra comandos", async ({ page }) => {
|
||||
await sendMessage(page, "!help");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 10_000,
|
||||
sender: "Asistente 2",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
expect(reply.toLowerCase()).toContain("help");
|
||||
expect(reply.toLowerCase()).toContain("ping");
|
||||
});
|
||||
|
||||
test("responde dentro del thread cuando se le habla por thread", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Este test necesita mas tiempo: enviar msg + esperar bot + thread + esperar bot en thread
|
||||
test.setTimeout(120_000);
|
||||
// 1. Enviar un mensaje normal (sera el thread root)
|
||||
await sendMessage(page, "Mensaje para iniciar thread");
|
||||
|
||||
// Esperar a que el bot responda al mensaje original
|
||||
await waitForBotReply(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Asistente 2",
|
||||
});
|
||||
|
||||
// 2. Enviar mensaje threaded via SDK (headless no soporta la hover action bar)
|
||||
await startThreadOnLastMessage(page);
|
||||
|
||||
// 3. Esperar que el bot responda DENTRO del thread
|
||||
// Usar el SDK para verificar que hay una respuesta en el thread
|
||||
const threadReply = await waitForThreadReplyViaSdk(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Asistente 2",
|
||||
});
|
||||
|
||||
expect(threadReply).toBeTruthy();
|
||||
expect(threadReply.length).toBeGreaterThan(5);
|
||||
});
|
||||
|
||||
test("no hay errores de E2EE en el timeline", async ({ page }) => {
|
||||
await assertNoDecryptionErrors(page);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import { test, expect, handleElementDialogs } from "../fixtures/persistent-context";
|
||||
import {
|
||||
goToRoom,
|
||||
sendMessage,
|
||||
waitForBotReply,
|
||||
assertNoDecryptionErrors,
|
||||
} from "../fixtures/matrix-room";
|
||||
|
||||
test.describe("assistant-bot", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await handleElementDialogs(page);
|
||||
await goToRoom(page, "Assistant");
|
||||
});
|
||||
|
||||
test("responde a un saludo en DM", async ({ page }) => {
|
||||
await sendMessage(page, "Hola, como estas?");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Assistant",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
expect(reply.length).toBeGreaterThan(10);
|
||||
});
|
||||
|
||||
test("responde a una pregunta con contenido coherente", async ({ page }) => {
|
||||
await sendMessage(page, "Que es la fotosintesis? Responde en una frase.");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Assistant",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
expect(reply.length).toBeGreaterThan(10);
|
||||
});
|
||||
|
||||
test("!help muestra lista de comandos", async ({ page }) => {
|
||||
await sendMessage(page, "!help");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 10_000,
|
||||
sender: "Assistant",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
expect(reply.toLowerCase()).toContain("help");
|
||||
expect(reply.toLowerCase()).toContain("ping");
|
||||
});
|
||||
|
||||
test("!ping responde", async ({ page }) => {
|
||||
await sendMessage(page, "!ping");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 10_000,
|
||||
sender: "Assistant",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
});
|
||||
|
||||
test("no hay errores de E2EE en el timeline", async ({ page }) => {
|
||||
await assertNoDecryptionErrors(page);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import { test, expect, handleElementDialogs } from "../fixtures/persistent-context";
|
||||
import { assertNoDecryptionErrors } from "../fixtures/matrix-room";
|
||||
|
||||
test.describe("Login y sesion E2EE", () => {
|
||||
test("sesion cargada — rooms visibles en sidebar", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await handleElementDialogs(page);
|
||||
|
||||
// Si llegamos aqui, handleElementDialogs ya verifico rooms sidebar
|
||||
const rooms = page.locator('[role="treeitem"], .mx_RoomTile');
|
||||
const roomCount = await rooms.count();
|
||||
expect(roomCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("no hay mensajes Unable to decrypt en rooms recientes", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
await handleElementDialogs(page);
|
||||
|
||||
// Abrir el primer room visible para verificar mensajes
|
||||
const firstRoom = page.locator('[role="treeitem"], .mx_RoomTile').first();
|
||||
const roomCount = await firstRoom.count();
|
||||
|
||||
if (roomCount > 0) {
|
||||
await firstRoom.click();
|
||||
await page.waitForTimeout(3_000);
|
||||
await assertNoDecryptionErrors(page);
|
||||
}
|
||||
});
|
||||
|
||||
test("helpers de room navegan correctamente", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await handleElementDialogs(page);
|
||||
|
||||
const rooms = page.locator('[role="treeitem"], .mx_RoomTile');
|
||||
const roomCount = await rooms.count();
|
||||
expect(roomCount).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user