Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/features/catalog/AgencyGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const CATEGORIES: Category[] = [
"content",
"research",
"business",
"learning",
];

/** A fixed color per role, so the mascots tell the cards apart. */
Expand Down
8 changes: 4 additions & 4 deletions app/src/features/catalog/agency.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("the Bot agency", () => {

fireEvent.click(within(invite).getByRole("button", { name: "See all bots" }));
const dialog = await screen.findByRole("dialog", { name: "Bot agency" });
expect(await within(dialog).findAllByRole("listitem")).toHaveLength(52);
expect(await within(dialog).findAllByRole("listitem")).toHaveLength(58);
});

test("a crew with only its chief invites the owner to pick bots, and a click adds one", async () => {
Expand Down Expand Up @@ -82,15 +82,15 @@ describe("the Bot agency", () => {
await openCrewWithChief();
fireEvent.click(screen.getByRole("button", { name: "Bot agency" }));
const dialog = await screen.findByRole("dialog", { name: "Bot agency" });
expect(await within(dialog).findAllByRole("listitem")).toHaveLength(52);
expect(await within(dialog).findAllByRole("listitem")).toHaveLength(58);

fireEvent.click(within(dialog).getByRole("button", { name: "Marketing & sales" }));
expect(within(dialog).getAllByRole("listitem")).toHaveLength(18);
fireEvent.click(within(dialog).getByRole("button", { name: "Product & management" }));
expect(within(dialog).getAllByRole("listitem")).toHaveLength(14);

fireEvent.click(within(dialog).getByRole("button", { name: "Research" }));
expect(within(dialog).getAllByRole("listitem")).toHaveLength(2);
expect(within(dialog).getAllByRole("listitem")).toHaveLength(4);
expect(
within(dialog).getByRole("button", { name: "Research" }).getAttribute("aria-pressed"),
).toBe("true");
Expand Down Expand Up @@ -129,7 +129,7 @@ describe("the Bot agency", () => {
expect(addCalls(fake)[0]).toMatchObject({ templateId: "code-reviewer" });

fireEvent.click(within(dialog).getByRole("button", { name: "Back to all bots" }));
expect(within(dialog).getAllByRole("listitem")).toHaveLength(52);
expect(within(dialog).getAllByRole("listitem")).toHaveLength(58);
});

test("the same role twice gets another name", async () => {
Expand Down
4 changes: 3 additions & 1 deletion app/src/i18n/en/catalog.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { base } from "./catalogBase";
import { contentAndLearning } from "./catalogContent";
import { engineering } from "./catalogEngineering";
import { marketing } from "./catalogMarketing";
import { product } from "./catalogProduct";
Expand Down Expand Up @@ -28,6 +29,7 @@ export const catalog = {
business: "Business",
product: "Product & management",
marketing: "Marketing & sales",
learning: "Learning",
},
none: "No bot matches that.",
loading: "Loading the bots…",
Expand All @@ -47,5 +49,5 @@ export const catalog = {
pairs: "Works well with",
technical: "What the bot is told when it starts",
},
roles: { ...base, ...product, ...marketing, ...engineering },
roles: { ...base, ...product, ...marketing, ...engineering, ...contentAndLearning },
};
62 changes: 62 additions & 0 deletions app/src/i18n/en/catalogContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Content, research and learning roles (spec 26.3): what the owner reads about each.

export const contentAndLearning = {
editor: {
name: "Editor",
role: "Edits and proofreads texts: fixes errors, tightens the writing and keeps the author's voice",
summary: "Fixes mistakes and tightens your writing while keeping it sounding like you",
about:
"Fixes spelling, grammar and clumsy sentences and cuts what is not needed, at the level you ask for: only mistakes, the wording or the structure too. It shows every change with the reason and never changes a fact, a number or a quote.",
when: "Before you publish or send anything that matters.",
pairs: "Fact Checker, to verify claims, and Writer, when a part needs rewriting.",
},
ghostwriter: {
name: "Ghostwriter",
role: "Writes in your voice: posts, speeches, bios and longer pieces that you will publish as your own",
summary:
"Writes in your voice what you will publish under your own name, from your ideas and stories",
about:
"Learns how you sound, draws out your stories and opinions with questions and writes drafts in your voice. It marks every gap it filled so you can confirm it, never invents experiences, and does not write work you must hand in as your own, like an exam or a thesis.",
when: "When you have things to say but not the time or the words.",
pairs: "Researcher, for facts, and Editor, to polish.",
},
"fact-checker": {
name: "Fact Checker",
role: "Checks claims against reliable sources and says how sure it is, or that it could not tell",
summary: "Checks whether a claim is true against reliable sources, and says how sure it is",
about:
"Takes the claims in a text and checks each one against the best sources it can find, preferring the original document. It gives a plain verdict with the link and how sure it is, and says honestly when it could not tell.",
when: "Before you publish, and whenever something you read sounds too good to be true.",
pairs: "Editor and Writer, who apply the corrections.",
},
"academic-researcher": {
name: "Academic Researcher",
role: "Finds and summarizes scholarly sources on a topic, with real citations and an honest account of the evidence",
summary:
"Finds and summarizes scholarly work on a topic, with real citations and an honest view of the evidence",
about:
"Finds papers, books and reports on your question, opens each one before citing it and summarizes the finding, the method and the limits. It never invents a reference, says when it only read an abstract, and does not write work you must hand in as your own.",
when: "When you need to know what the research really says about a topic.",
pairs: "Data Analyst, for the numbers in a study, and Writer, for a readable summary.",
},
tutor: {
name: "Tutor",
role: "Teaches a subject step by step, adapting to your level, and checks that you really understood",
summary:
"Teaches you a subject step by step, at your level, and checks that you really understood",
about:
"Finds out what you already know and teaches one idea at a time with examples from your world. It asks you to explain it back or try a small exercise, gives hints before answers and corrects kindly. It will not do your graded assignment for you.",
when: "When you want to learn a subject properly, or help someone who is studying.",
pairs: "Researcher, for sources, and Writer, for study notes.",
},
"language-teacher": {
name: "Language Teacher",
role: "Teaches a language through conversation, kind corrections, vocabulary and short exercises",
summary:
"Helps you learn a language by talking, with kind corrections, vocabulary and short exercises",
about:
"Holds conversations at your level in the language you are learning, corrects the mistakes that matter most with the rule in one line, teaches words in context and ends each session with a summary and a small exercise. It works from text, so it cannot hear your pronunciation.",
when: "When you want to practice a language every day, without shyness.",
pairs: "Translator, to check a difficult phrase, and Writer, for reading material.",
},
};
4 changes: 3 additions & 1 deletion app/src/i18n/es/catalog.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Messages } from "../en";
import { base } from "./catalogBase";
import { contentAndLearning } from "./catalogContent";
import { engineering } from "./catalogEngineering";
import { marketing } from "./catalogMarketing";
import { product } from "./catalogProduct";
Expand All @@ -25,6 +26,7 @@ export const catalog: Messages["catalog"] = {
business: "Negocios",
product: "Producto y gestión",
marketing: "Marketing y ventas",
learning: "Aprendizaje",
},
none: "Ningún bot coincide con eso.",
loading: "Cargando los bots…",
Expand All @@ -44,5 +46,5 @@ export const catalog: Messages["catalog"] = {
pairs: "Combina bien con",
technical: "Lo que recibe el bot cuando empieza",
},
roles: { ...base, ...product, ...marketing, ...engineering },
roles: { ...base, ...product, ...marketing, ...engineering, ...contentAndLearning },
};
63 changes: 63 additions & 0 deletions app/src/i18n/es/catalogContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { contentAndLearning as en } from "../en/catalogContent";

export const contentAndLearning: typeof en = {
editor: {
name: "Corrector de textos",
role: "Revisa y edita textos: corrige errores, depura la escritura y mantiene la voz del autor",
summary: "Corrige errores y depura tu escritura, manteniendo el estilo que suena a ti",
about:
"Corrige ortografía, gramática y frases torpes y recorta lo que sobra, en el nivel que pidas: solo los errores, la forma de decirlo o también la estructura. Muestra cada cambio con su motivo y nunca altera un dato, una cifra ni una cita.",
when: "Antes de publicar o enviar algo que importa.",
pairs:
"Verificador de datos, para comprobar afirmaciones, y Redactor, cuando una parte hay que rehacerla.",
},
ghostwriter: {
name: "Escritor fantasma",
role: "Escribe con tu voz: publicaciones, discursos, biografías breves y textos más largos que publicas como tuyos",
summary:
"Escribe con tu voz lo que vas a publicar con tu nombre, a partir de tus ideas e historias",
about:
"Aprende cómo suenas, te saca las historias y opiniones con preguntas y escribe borradores con tu voz. Marca cada hueco que rellenó para que lo confirmes, nunca inventa experiencias y no escribe trabajos que debes entregar como tuyos, como un examen o una tesis.",
when: "Cuando tienes algo que decir, pero no el tiempo ni las palabras.",
pairs: "Investigador, para los datos, y Corrector de textos, para pulir.",
},
"fact-checker": {
name: "Verificador de datos",
role: "Comprueba afirmaciones en fuentes fiables y dice qué tan seguro está, o que no pudo saberlo",
summary: "Comprueba si una afirmación es cierta en fuentes fiables y dice qué tan seguro está",
about:
"Toma las afirmaciones de un texto y comprueba cada una en las mejores fuentes que encuentre, prefiriendo el documento original. Da un veredicto con palabras sencillas, con el enlace y qué tan seguro está, y dice con honestidad cuando no pudo saberlo.",
when: "Antes de publicar, y siempre que algo que leíste suena demasiado bueno para ser cierto.",
pairs: "Corrector de textos y Redactor, que aplican las correcciones.",
},
"academic-researcher": {
name: "Investigador académico",
role: "Encuentra y resume fuentes académicas sobre un tema, con citas reales y un relato honesto de la evidencia",
summary:
"Encuentra y resume trabajos académicos sobre un tema, con citas reales y una visión honesta de la evidencia",
about:
"Encuentra artículos, libros e informes sobre tu pregunta, abre cada uno antes de citarlo y resume la conclusión, el método y los límites. Nunca inventa una referencia, dice cuando solo leyó el resumen y no escribe trabajos que debes entregar como tuyos.",
when: "Cuando necesitas saber qué dice realmente la investigación sobre un tema.",
pairs:
"Analista de datos, para los números de un estudio, y Redactor, para un resumen legible.",
},
tutor: {
name: "Tutor",
role: "Enseña un tema paso a paso, a tu nivel, y comprueba que de verdad entendiste",
summary: "Te enseña un tema paso a paso, a tu nivel, y comprueba que de verdad entendiste",
about:
"Descubre lo que ya sabes y enseña una idea a la vez, con ejemplos de tu mundo. Te pide que se lo expliques de vuelta o hagas un ejercicio pequeño, da pistas antes que respuestas y corrige con amabilidad. No hace por ti tu trabajo con nota.",
when: "Cuando quieres aprender un tema bien, o ayudar a alguien que estudia.",
pairs: "Investigador, para fuentes, y Redactor, para apuntes de estudio.",
},
"language-teacher": {
name: "Profesor de idiomas",
role: "Enseña un idioma con conversación, correcciones amables, vocabulario y ejercicios cortos",
summary:
"Te ayuda a aprender un idioma conversando, con correcciones amables, vocabulario y ejercicios cortos",
about:
"Conversa contigo al nivel adecuado en el idioma que aprendes, corrige los errores que más importan con la regla en una línea, enseña palabras en contexto y termina cada sesión con un resumen y un ejercicio pequeño. Trabaja con texto, así que no oye tu pronunciación.",
when: "Cuando quieres practicar un idioma todos los días, sin vergüenza.",
pairs: "Traductor, para comprobar una frase difícil, y Redactor, para material de lectura.",
},
};
4 changes: 3 additions & 1 deletion app/src/i18n/pt-BR/catalog.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Messages } from "../en";
import { base } from "./catalogBase";
import { contentAndLearning } from "./catalogContent";
import { engineering } from "./catalogEngineering";
import { marketing } from "./catalogMarketing";
import { product } from "./catalogProduct";
Expand All @@ -25,6 +26,7 @@ export const catalog: Messages["catalog"] = {
business: "Negócios",
product: "Produto e gestão",
marketing: "Marketing e vendas",
learning: "Aprendizado",
},
none: "Nenhum bot combina com isso.",
loading: "Carregando os bots…",
Expand All @@ -44,5 +46,5 @@ export const catalog: Messages["catalog"] = {
pairs: "Combina bem com",
technical: "O que o bot recebe quando começa",
},
roles: { ...base, ...product, ...marketing, ...engineering },
roles: { ...base, ...product, ...marketing, ...engineering, ...contentAndLearning },
};
64 changes: 64 additions & 0 deletions app/src/i18n/pt-BR/catalogContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { contentAndLearning as en } from "../en/catalogContent";

export const contentAndLearning: typeof en = {
editor: {
name: "Revisor de texto",
role: "Revisa e edita textos: corrige erros, enxuga a escrita e mantém a voz do autor",
summary: "Corrige erros e enxuga a sua escrita, mantendo o jeito que soa como você",
about:
"Corrige ortografia, gramática e frases desajeitadas e corta o que sobra, no nível que você pedir: só os erros, o jeito de dizer ou também a estrutura. Mostra cada mudança com o motivo e nunca altera um fato, um número nem uma citação.",
when: "Antes de publicar ou enviar qualquer coisa que importa.",
pairs:
"Checador de fatos, para verificar afirmações, e Redator, quando uma parte precisa ser refeita.",
},
ghostwriter: {
name: "Escritor fantasma",
role: "Escreve na sua voz: posts, discursos, minibiografias e textos mais longos que você publica como seus",
summary:
"Escreve na sua voz o que você vai publicar com o seu nome, a partir das suas ideias e histórias",
about:
"Aprende como você soa, tira de você as histórias e opiniões com perguntas e escreve rascunhos na sua voz. Marca cada lacuna que preencheu para você confirmar, nunca inventa experiências e não escreve trabalhos que você precisa entregar como seus, como uma prova ou uma tese.",
when: "Quando você tem o que dizer, mas não tem tempo nem as palavras.",
pairs: "Pesquisador, para os fatos, e Revisor de texto, para polir.",
},
"fact-checker": {
name: "Checador de fatos",
role: "Confere afirmações em fontes confiáveis e diz o quanto tem certeza, ou que não deu para saber",
summary:
"Confere se uma afirmação é verdadeira em fontes confiáveis e diz o quanto tem certeza",
about:
"Pega as afirmações de um texto e confere cada uma nas melhores fontes que achar, preferindo o documento original. Dá um veredito em palavras simples, com o link e o quanto tem certeza, e diz com honestidade quando não deu para saber.",
when: "Antes de publicar, e sempre que algo que você leu parece bom demais para ser verdade.",
pairs: "Revisor de texto e Redator, que aplicam as correções.",
},
"academic-researcher": {
name: "Pesquisador acadêmico",
role: "Encontra e resume fontes acadêmicas sobre um tema, com citações reais e um relato honesto das evidências",
summary:
"Encontra e resume trabalhos acadêmicos sobre um tema, com citações reais e uma visão honesta das evidências",
about:
"Encontra artigos, livros e relatórios sobre a sua pergunta, abre cada um antes de citar e resume a conclusão, o método e os limites. Nunca inventa uma referência, diz quando só leu o resumo e não escreve trabalhos que você precisa entregar como seus.",
when: "Quando você precisa saber o que a pesquisa realmente diz sobre um tema.",
pairs: "Analista de dados, para os números de um estudo, e Redator, para um resumo legível.",
},
tutor: {
name: "Tutor",
role: "Ensina um assunto passo a passo, no seu nível, e confere se você realmente entendeu",
summary:
"Ensina um assunto a você passo a passo, no seu nível, e confere se você realmente entendeu",
about:
"Descobre o que você já sabe e ensina uma ideia de cada vez, com exemplos do seu mundo. Pede para você explicar de volta ou fazer um exercício pequeno, dá dicas antes das respostas e corrige com gentileza. Não faz o seu trabalho valendo nota por você.",
when: "Quando você quer aprender um assunto direito, ou ajudar alguém que está estudando.",
pairs: "Pesquisador, para fontes, e Redator, para resumos de estudo.",
},
"language-teacher": {
name: "Professor de idiomas",
role: "Ensina um idioma por meio de conversa, correções gentis, vocabulário e exercícios curtos",
summary:
"Ajuda você a aprender um idioma conversando, com correções gentis, vocabulário e exercícios curtos",
about:
"Conversa com você no nível certo no idioma que você está aprendendo, corrige os erros que mais importam com a regra em uma linha, ensina palavras no contexto e termina cada sessão com um resumo e um exercício pequeno. Trabalha com texto, então não ouve a sua pronúncia.",
when: "Quando você quer praticar um idioma todo dia, sem vergonha.",
pairs: "Tradutor, para conferir uma frase difícil, e Redator, para material de leitura.",
},
};
2 changes: 1 addition & 1 deletion app/src/lib/fakeCatalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { FakeBotloft } from "./fake";
describe("the fake's bot catalog", () => {
it("lists the roles, by category too, and reads one with its instructions", async () => {
const fake = new FakeBotloft();
expect(await fake.call("catalog.list", {})).toHaveLength(52);
expect(await fake.call("catalog.list", {})).toHaveLength(58);
const product = await fake.call("catalog.list", { category: "product" });
expect(product).toHaveLength(14);
expect(await fake.call("catalog.list", { category: "marketing" })).toHaveLength(18);
Expand Down
6 changes: 6 additions & 0 deletions app/src/lib/fakeCatalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ const ROLES: [id: string, category: BotTemplateCategory, name: string, effort?:
["devops-engineer", "code", "DevOps Engineer"],
["security-reviewer", "code", "Security Reviewer", "high"],
["data-engineer", "code", "Data Engineer"],
["editor", "content", "Editor"],
["ghostwriter", "content", "Ghostwriter"],
["fact-checker", "research", "Fact Checker"],
["academic-researcher", "research", "Academic Researcher"],
["tutor", "learning", "Tutor"],
["language-teacher", "learning", "Language Teacher"],
];

/** Every role, as `catalog.get` returns it. */
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/protocol.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,7 @@ export type CrewAccessIdParams = { accessId: CrewAccessId, };
/**
* The group a role is listed under.
*/
export type BotTemplateCategory = "code" | "design" | "content" | "research" | "business" | "product" | "marketing";
export type BotTemplateCategory = "code" | "design" | "content" | "research" | "business" | "product" | "marketing" | "learning";

/**
* A role as the list shows it, in English. The app writes the name, role
Expand Down
1 change: 1 addition & 0 deletions crates/botloft-core/src/protocol/catalog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ text_enum!(
Business => "business",
Product => "product",
Marketing => "marketing",
Learning => "learning",
}
);

Expand Down
Loading
Loading