Comments
import { Aside } from ‘@astrojs/starlight/components’;
Comentarios anidados en tiempo real, asociados a un artefacto o a cualquier contexto
dentro de él. Accedé vía sdk.comments.
Envelope de respuesta
Sección titulada «Envelope de respuesta»Las respuestas del data API usan:
{ "success": true, "data": { "comments": [/* … */], "count": N } }Leé data.comments, no comments en la raíz.
Comentarios en archivos
Sección titulada «Comentarios en archivos»Los hilos de un archivo viven en el artefacto bucket del workspace, con
contextId obligatorio file:<deliverableId>. Sin ese contexto: 400 FILE_CONTEXT_REQUIRED.
No hay WebSocket en buckets (la UI recarga al abrir).
Ver la guía completa en inglés: Comments (EN).
Métodos
Sección titulada «Métodos»// CRUDadd(options: { content: string; contextId?: string; parentId?: string; authorName?: string; position?: CommentPosition; state?: unknown; mentions?: string[];}): Promise<Comment>
reply(parentId: string, content: string, authorName?: string): Promise<Comment>edit(id: string, content: string): Promise<Comment>delete(id: string): Promise<boolean>findById(id: string): Promise<Comment | null>getReplies(parentId: string): Promise<Comment[]>getThread(rootId: string): Promise<CommentThread>
// Configuración (solo owner)getConfig(): Promise<CommentsConfig>setConfig(config: Partial<CommentsConfig>): Promise<CommentsConfig>
// Tiempo realsubscribe(handler: (event: CommentEvent) => void): () => voidsubscribeToContext(contextId: string, handler: (event: CommentEvent) => void): () => voiddisconnect(): void
// Action items (sesión requerida)resolve(id: string, resolved?: boolean): Promise<Comment>assign(id: string, options?: { assignee?: string | null; dueAt?: string | null }): Promise<Comment>
// State bridge (comentarios anclados)onCaptureState(fn: () => unknown | Promise<unknown>): voidonRestoreState(fn: (state: unknown) => void | Promise<void>): voidQuery builder
Sección titulada «Query builder»find(filter?: { contextId?: string; parentId?: string | null }): CommentsQuery
query.context(contextId: string): CommentsQueryquery.topLevel(): CommentsQueryquery.sort(field: 'createdAt' | 'updatedAt', order: 'asc' | 'desc'): CommentsQueryquery.limit(n: number): CommentsQueryquery.skip(n: number): CommentsQueryquery.exec(): Promise<Comment[]>interface Comment { id: string; contextId: string | null; parentId: string | null; authorId: string | null; authorName: string; content: string; createdAt: string; updatedAt: string; resolved?: boolean; resolvedBy?: string | null; resolvedAt?: string | null; position?: CommentPosition | null; state?: unknown | null; mentions?: string[]; // Campos de action item (presentes si está asignado) assigneeUserId?: string | null; assigneeEmail?: string | null; dueAt?: string | null;}
interface CommentsConfig { enabled: boolean; identityMode: 'anonymous' | 'named' | 'authenticated'; allowReplies: boolean; maxDepth: number; overlayEnabled?: boolean;}
interface CommentEvent { type: 'comment:added' | 'comment:updated' | 'comment:deleted' | 'comment:resolved'; comment: Comment;}
interface CommentThread { comment: Comment; replies: CommentThread[];}
interface CommentPosition { selector?: string; relX?: number; relY?: number; pctX?: number; pctY?: number; scrollY?: number;}Ejemplos
Sección titulada «Ejemplos»// Configurar (solo owner)await sdk.comments.setConfig({ enabled: true, identityMode: 'named', allowReplies: true, maxDepth: 3,});
// Agregar un comentario anclado a un slideconst comment = await sdk.comments.add({ content: '¡Buen gráfico!', contextId: 'slide-5', authorName: 'Alice',});
// Responderawait sdk.comments.reply(comment.id, '¡Gracias!', 'Bob');
// Consultar comentarios de primer nivel para un contextoconst comments = await sdk.comments .find({ contextId: 'slide-5' }) .topLevel() .sort('createdAt', 'desc') .limit(50) .exec();
// Obtener el hilo completo anidadoconst thread = await sdk.comments.getThread(comment.id);
// Actualizaciones en tiempo realconst unsub = sdk.comments.subscribeToContext('slide-5', (event) => { if (event.type === 'comment:added') renderComment(event.comment);});// Más tarde:unsub();State bridge
Sección titulada «State bridge»Los comentarios anclados pueden capturar y restaurar el estado de la app (p. ej., filtros activos de un dashboard). Registrá los callbacks antes de agregar comentarios:
sdk.comments.onCaptureState(() => ({ filters: currentFilters, activeTab,}));
sdk.comments.onRestoreState((state) => { currentFilters = state.filters; activeTab = state.activeTab;});Al agregar un comentario se almacena el estado actual. Al abrir un comentario anclado se
reproduce el estado vía onRestoreState.
Action items
Sección titulada «Action items»Cualquier comentario puede convertirse en un action item asignándolo a un miembro o colaborador del workspace. El asignado recibe un email (y un mensaje de Telegram si tiene la cuenta vinculada). Al resolver el comentario, el solicitante recibe una notificación y puede reabrirlo con un clic.
En el viewer del artefacto: abrí el panel de comentarios → botón Assign → elegí una persona y, opcionalmente, una fecha límite.
Vía API:
# Asignar al crearPOST /v1/data/{artifactId}/comments{ "content": "Corregir el eje Y", "assignee": "alice@example.com", "dueAt": "2025-08-01T00:00:00Z" }
# Asignar o desasignar un comentario existentePATCH /v1/data/{artifactId}/comments/{id}/assign{ "assignee": "alice@example.com", "dueAt": "2025-08-01T00:00:00Z" }
# DesasignarPATCH /v1/data/{artifactId}/comments/{id}/assign{ "assignee": null }El assignee debe estar en el conjunto de personas del artefacto (miembros del workspace
- colaboradores); las direcciones desconocidas devuelven
400 ASSIGNEE_NOT_FOUND.
Seguimiento: todos ven sus action items abiertos en la campana de notificaciones del Home — ordenados por fecha límite, los vencidos resaltados, con botones Hecho y Reabrir inline.
Filtrar por asignado:
GET /v1/data/{artifactId}/comments?assignee=meGET /v1/data/{artifactId}/comments?assignee=alice@example.comHerramientas de crew IA: action_item_create, action_item_list.
Toolbar del viewer (UI integrada)
Sección titulada «Toolbar del viewer (UI integrada)»Con comentarios habilitados en un artefacto, los viewers logueados ven una toolbar flotante:
| Función | Notas |
|---|---|
| Badge de no leídos | Se actualiza por WebSocket antes de abrir el panel |
| Filtros Abiertos / Resueltos | Cambiá la vista del hilo |
| Reacciones | 👍 ❤️ ✅ 🎉 👀 en cualquier comentario |
| Indicadores de escritura | Ves cuando alguien está escribiendo |
| Presencia | “N otros acá” en el encabezado (canal de comments, no analytics de página) |
| Resolver / Reabrir | Marcá hilos como hechos sin borrarlos |
Owners y colaboradores también gestionan hilos desde la pestaña Comments del Inspector del workspace.
Pedirle cambios a la IA desde un comentario
Sección titulada «Pedirle cambios a la IA desde un comentario»Escribí @IA (también @AI o @ShareOut) en un comentario o respuesta, seguido del
cambio: @IA cambiá el gráfico a barras y agregá el total. El editor del artefacto hace
el cambio, lo publica como una nueva versión (se deshace desde el historial de
versiones) y responde en el mismo hilo: un “Estoy en eso…” que pasa a ser el resumen de
lo que cambió, o el motivo por el que no pudo.
- Solo el dueño o un editor del artefacto puede pedir cambios. El resto (viewers, anónimos o externos) recibe una respuesta avisando que necesita permiso de edición.
- Cuenta contra los mismos límites que las otras publicaciones con IA: el límite de chat con IA por usuario, el límite diario de publicaciones y la cuota de almacenamiento del dueño.
- Requiere un editor de IA configurado para el artefacto (igual que la edición en Studio).
- No disponible en comentarios de archivos.
Overlay del viewer
Sección titulada «Overlay del viewer»Según identityMode en _comments_config:
| Modo | Quién ve el panel |
|---|---|
anonymous (default) |
Cualquiera — nombre opcional |
named |
Cualquiera — nombre obligatorio al publicar |
authenticated |
Solo firmados (invitados ven Log in to comment) |
Comentarios de invitados (sin cuenta)
Sección titulada «Comentarios de invitados (sin cuenta)»Si el dueño los activa (PUT /v1/data/{artifactId}/comments/_config con
{ "guestComments": true }, o para una carpeta PUT /v1/workspaces/{wid}/folders/{fid}/guest-comments
con { "enabled": true }; MCP: set_guest_comments), quien revisa por un link puede comentar sin
crear una cuenta: la toolbar muestra Comentá como invitado (nombre, email y un código de 6
dígitos).
En la app, quien administra la carpeta activa Permitir comentarios de invitados en el panel Quién tiene acceso de la carpeta, y el dueño elige Seguir la carpeta / Sí / No en la pestaña Comentarios del artefacto, que también muestra si los invitados pueden comentar ahora.
- Solo donde ya puede abrir el artefacto sin cuenta: público, o con contraseña ya desbloqueada. Los privados y de workspace siguen pidiendo cuenta.
- El código da una cookie HttpOnly y SameSite=Strict de 12 horas, válida solo para ese artefacto. El email se guarda como hash con clave y nunca se devuelve.
- Los invitados comentan y responden; no resuelven, asignan, reaccionan, aprueban ni mencionan. El dueño puede borrar sus comentarios.
Avisos: el dueño se entera cuando alguien aprueba una versión, y quienes siguen o colaboran en el artefacto, cuando hay versiones nuevas (un aviso por artefacto cuando se deja de publicar por 10 minutos, con la nota de cada versión). Nunca le avisamos a quien hizo la acción; el mail respeta la preferencia de mails de producto y su link para darse de baja.
En artefactos private / workspace el WebSocket exige sesión. Los archivos usan
contextId=file:… y no tienen realtime.
Guía completa (EN): Comments.
