refactor: Optimize token usage in canvas tool schemas and responses

This commit is contained in:
2026-02-17 02:46:24 -06:00
parent c0e616212d
commit a217f6e58e
2 changed files with 42 additions and 42 deletions

View File

@@ -337,33 +337,33 @@ export function createCanvasHandlers(): ToolConfig[] {
schema: { schema: {
type: 'object', type: 'object',
properties: { properties: {
id: { type: 'string', description: 'ID de la ventana a inspeccionar' }, id: { type: 'string', description: 'ID de la ventana' },
selector: { type: 'string', description: 'Selector CSS para filtrar elementos dentro de la ventana (opcional)' }, selector: { type: 'string', description: 'Selector CSS dentro de la ventana' },
attribute: { attribute: {
type: 'string', type: 'string',
enum: ['innerHTML', 'outerHTML', 'textContent', 'attributes'], enum: ['innerHTML', 'outerHTML', 'textContent', 'attributes'],
description: 'Que retornar: innerHTML (default), outerHTML, textContent, attributes' description: 'Que retornar (default: innerHTML)'
}, },
limit: { type: 'number', description: 'Limitar caracteres de salida (default: 2000)' } limit: { type: 'number', description: 'Max caracteres (default: 2000)' }
}, },
required: ['id'] required: ['id']
}, },
handler: (args: { id: string; selector?: string; attribute?: string; limit?: number }) => { handler: (args: { id: string; selector?: string; attribute?: string; limit?: number }) => {
const windowEl = document.querySelector(`[data-window-id="${args.id}"]`) const windowEl = document.querySelector(`[data-window-id="${args.id}"]`)
if (!windowEl) { if (!windowEl) {
return `Error: Ventana "${args.id}" no encontrada` return `Error: window ${args.id} not found`
} }
const content = windowEl.querySelector('.window-content') const content = windowEl.querySelector('.window-content')
if (!content) { if (!content) {
return `Error: Contenido de ventana "${args.id}" no encontrado` return `Error: no content in ${args.id}`
} }
let target: Element | null = content let target: Element | null = content
if (args.selector) { if (args.selector) {
target = content.querySelector(args.selector) target = content.querySelector(args.selector)
if (!target) { if (!target) {
return `Error: Selector "${args.selector}" no encontrado en ventana "${args.id}"` return `Error: no match ${args.selector} in ${args.id}`
} }
} }
@@ -382,7 +382,7 @@ export function createCanvasHandlers(): ToolConfig[] {
} }
if (result.length > limit) { if (result.length > limit) {
result = result.slice(0, limit) + `\n... (truncado, ${result.length - limit} chars mas)` result = result.slice(0, limit) + `\n...(+${result.length - limit})`
} }
return result return result
@@ -390,19 +390,19 @@ export function createCanvasHandlers(): ToolConfig[] {
}, },
{ {
name: 'get_canvas', name: 'get_canvas',
description: 'Lee elementos del canvas usando selectores CSS. Similar a Read pero para el DOM.', description: 'Lee elementos del canvas con selector CSS',
category: 'canvas', category: 'canvas',
schema: { schema: {
type: 'object', type: 'object',
properties: { properties: {
selector: { type: 'string', description: 'Selector CSS para encontrar elementos' }, selector: { type: 'string', description: 'Selector CSS' },
attribute: { attribute: {
type: 'string', type: 'string',
enum: ['innerHTML', 'outerHTML', 'textContent', 'attributes', 'style', 'classList'], enum: ['innerHTML', 'outerHTML', 'textContent', 'attributes', 'style', 'classList'],
description: 'Que retornar (default: innerHTML)' description: 'Que retornar (default: innerHTML)'
}, },
all: { type: 'boolean', description: 'Si true, retorna todos los matches (default: false, solo el primero)' }, all: { type: 'boolean', description: 'Retorna todos los matches (default: false)' },
limit: { type: 'number', description: 'Limitar caracteres de salida (default: 3000)' } limit: { type: 'number', description: 'Max caracteres (default: 3000)' }
}, },
required: ['selector'] required: ['selector']
}, },
@@ -434,20 +434,20 @@ export function createCanvasHandlers(): ToolConfig[] {
if (args.all) { if (args.all) {
const elements = container.querySelectorAll(args.selector) const elements = container.querySelectorAll(args.selector)
if (elements.length === 0) { if (elements.length === 0) {
return `No se encontraron elementos con selector "${args.selector}"` return `No match: ${args.selector}`
} }
const values = Array.from(elements).map((el, i) => `[${i}] ${extractValue(el)}`) const values = Array.from(elements).map((el, i) => `[${i}] ${extractValue(el)}`)
result = `Encontrados ${elements.length} elementos:\n${values.join('\n---\n')}` result = `${elements.length} elements:\n${values.join('\n---\n')}`
} else { } else {
const el = container.querySelector(args.selector) const el = container.querySelector(args.selector)
if (!el) { if (!el) {
return `No se encontro elemento con selector "${args.selector}"` return `No match: ${args.selector}`
} }
result = extractValue(el) result = extractValue(el)
} }
if (result.length > limit) { if (result.length > limit) {
result = result.slice(0, limit) + `\n... (truncado, ${result.length - limit} chars mas)` result = result.slice(0, limit) + `\n...(+${result.length - limit})`
} }
return result return result
@@ -455,20 +455,20 @@ export function createCanvasHandlers(): ToolConfig[] {
}, },
{ {
name: 'edit_canvas', name: 'edit_canvas',
description: 'Edita elementos del canvas. Similar a Edit pero para el DOM. Reemplaza old_value por new_value.', description: 'Edita elementos del canvas (old_value -> new_value)',
category: 'canvas', category: 'canvas',
schema: { schema: {
type: 'object', type: 'object',
properties: { properties: {
selector: { type: 'string', description: 'Selector CSS del elemento a editar' }, selector: { type: 'string', description: 'Selector CSS' },
attribute: { attribute: {
type: 'string', type: 'string',
enum: ['innerHTML', 'textContent', 'outerHTML', 'style', 'className'], enum: ['innerHTML', 'textContent', 'outerHTML', 'style', 'className'],
description: 'Que atributo editar (default: innerHTML)' description: 'Que atributo editar (default: innerHTML)'
}, },
old_value: { type: 'string', description: 'Valor a buscar y reemplazar (si no se pasa, reemplaza todo)' }, old_value: { type: 'string', description: 'Si se omite, reemplaza todo' },
new_value: { type: 'string', description: 'Nuevo valor' }, new_value: { type: 'string', description: 'Nuevo valor' },
all: { type: 'boolean', description: 'Si true, edita todos los matches (default: false)' } all: { type: 'boolean', description: 'Edita todos los matches (default: false)' }
}, },
required: ['selector', 'new_value'] required: ['selector', 'new_value']
}, },
@@ -482,7 +482,7 @@ export function createCanvasHandlers(): ToolConfig[] {
: [container.querySelector(args.selector)].filter(Boolean) as Element[] : [container.querySelector(args.selector)].filter(Boolean) as Element[]
if (elements.length === 0) { if (elements.length === 0) {
return `Error: No se encontro elemento con selector "${args.selector}"` return `Error: no match ${args.selector}`
} }
let editedCount = 0 let editedCount = 0
@@ -513,25 +513,25 @@ export function createCanvasHandlers(): ToolConfig[] {
} }
if (editedCount === 0) { if (editedCount === 0) {
return `Error: old_value "${args.old_value}" no encontrado en ningun elemento` return `Error: old_value not found`
} }
return `Editado ${editedCount} elemento(s) con selector "${args.selector}"` return `OK ${editedCount} edited`
} }
}, },
{ {
name: 'canvas_css', name: 'canvas_css',
description: 'Inyecta CSS en el canvas. Usa id para poder actualizar o remover despues.', description: 'Inyecta CSS en el canvas',
category: 'canvas', category: 'canvas',
schema: { schema: {
type: 'object', type: 'object',
properties: { properties: {
css: { type: 'string', description: 'Codigo CSS a inyectar' }, css: { type: 'string', description: 'Codigo CSS' },
id: { type: 'string', description: 'ID unico para el bloque de estilos (default: auto)' }, id: { type: 'string', description: 'ID del bloque (default: auto)' },
mode: { mode: {
type: 'string', type: 'string',
enum: ['inject', 'replace', 'remove'], enum: ['inject', 'replace', 'remove'],
description: 'inject (default), replace (reemplaza si existe), remove (elimina por id)' description: 'inject (default), replace, remove'
} }
}, },
required: ['css'] required: ['css']
@@ -541,20 +541,20 @@ export function createCanvasHandlers(): ToolConfig[] {
const styleId = args.id ? `canvas-css-${args.id}` : `canvas-css-${Date.now()}` const styleId = args.id ? `canvas-css-${args.id}` : `canvas-css-${Date.now()}`
if (mode === 'remove') { if (mode === 'remove') {
if (!args.id) return 'Error: Se requiere id para remover' if (!args.id) return 'Error: id required for remove'
const existing = document.getElementById(`canvas-css-${args.id}`) const existing = document.getElementById(`canvas-css-${args.id}`)
if (existing) { if (existing) {
existing.remove() existing.remove()
return `CSS "${args.id}" removido` return `OK css:${args.id} removed`
} }
return `Error: CSS "${args.id}" no encontrado` return `Error: css:${args.id} not found`
} }
let styleEl = args.id ? document.getElementById(`canvas-css-${args.id}`) : null let styleEl = args.id ? document.getElementById(`canvas-css-${args.id}`) : null
if (mode === 'replace' && styleEl) { if (mode === 'replace' && styleEl) {
styleEl.textContent = args.css styleEl.textContent = args.css
return `CSS "${args.id}" actualizado` return `OK css:${args.id} replaced`
} }
if (!styleEl) { if (!styleEl) {
@@ -564,18 +564,18 @@ export function createCanvasHandlers(): ToolConfig[] {
} }
styleEl.textContent = args.css styleEl.textContent = args.css
return `CSS inyectado con id "${styleId.replace('canvas-css-', '')}"` return `OK css:${styleId.replace('canvas-css-', '')}`
} }
}, },
{ {
name: 'canvas_js', name: 'canvas_js',
description: 'Ejecuta JavaScript en el contexto del canvas. Tiene acceso a las ventanas y el DOM.', description: 'Ejecuta JavaScript en el contexto del canvas',
category: 'canvas', category: 'canvas',
schema: { schema: {
type: 'object', type: 'object',
properties: { properties: {
code: { type: 'string', description: 'Codigo JavaScript a ejecutar' }, code: { type: 'string', description: 'Codigo JavaScript a ejecutar' },
async: { type: 'boolean', description: 'Si true, ejecuta como async y espera resultado' } async: { type: 'boolean', description: 'Ejecutar como async (default: false)' }
}, },
required: ['code'] required: ['code']
}, },
@@ -610,26 +610,26 @@ export function createCanvasHandlers(): ToolConfig[] {
}, },
{ {
name: 'get_canvas_css', name: 'get_canvas_css',
description: 'Obtiene los bloques CSS inyectados en el canvas.', description: 'Obtiene CSS inyectado',
category: 'canvas', category: 'canvas',
schema: { schema: {
type: 'object', type: 'object',
properties: { properties: {
id: { type: 'string', description: 'ID especifico del bloque CSS (opcional, si no se pasa lista todos)' } id: { type: 'string', description: 'ID del bloque (si se omite, lista todos)' }
}, },
required: [] required: []
}, },
handler: (args: { id?: string }) => { handler: (args: { id?: string }) => {
if (args.id) { if (args.id) {
const styleEl = document.getElementById(`canvas-css-${args.id}`) const styleEl = document.getElementById(`canvas-css-${args.id}`)
if (!styleEl) return `Error: CSS "${args.id}" no encontrado` if (!styleEl) return `Error: css:${args.id} not found`
return styleEl.textContent || '(vacio)' return styleEl.textContent || '(empty)'
} }
// Listar todos // Listar todos
const styles = document.querySelectorAll('style[id^="canvas-css-"]') const styles = document.querySelectorAll('style[id^="canvas-css-"]')
if (styles.length === 0) { if (styles.length === 0) {
return 'No hay CSS inyectado en el canvas' return 'No CSS injected'
} }
const list = Array.from(styles).map(s => { const list = Array.from(styles).map(s => {
@@ -638,7 +638,7 @@ export function createCanvasHandlers(): ToolConfig[] {
return `- ${id}: ${preview}${(s.textContent?.length || 0) > 100 ? '...' : ''}` return `- ${id}: ${preview}${(s.textContent?.length || 0) > 100 ? '...' : ''}`
}).join('\n') }).join('\n')
return `CSS inyectados (${styles.length}):\n${list}` return `${styles.length} blocks:\n${list}`
} }
} }
] ]

View File

@@ -24,12 +24,12 @@ export const ALL_TOOL_METAS: ToolMeta[] = [
{ name: 'resize_window', description: 'Cambia el tamano de una ventana', category: 'canvas' }, { name: 'resize_window', description: 'Cambia el tamano de una ventana', category: 'canvas' },
{ name: 'close_window', description: 'Cierra una ventana del canvas', category: 'canvas' }, { name: 'close_window', description: 'Cierra una ventana del canvas', category: 'canvas' },
{ name: 'list_windows', description: 'Lista todas las ventanas abiertas', category: 'canvas' }, { name: 'list_windows', description: 'Lista todas las ventanas abiertas', category: 'canvas' },
{ name: 'inspect_window', description: 'Inspecciona el HTML de una ventana', category: 'canvas' }, { name: 'inspect_window', description: 'Inspecciona el contenido de una ventana', category: 'canvas' },
{ name: 'get_canvas', description: 'Lee elementos del canvas con selector CSS', category: 'canvas' }, { name: 'get_canvas', description: 'Lee elementos del canvas con selector CSS', category: 'canvas' },
{ name: 'edit_canvas', description: 'Edita elementos del canvas (old_value -> new_value)', category: 'canvas' }, { name: 'edit_canvas', description: 'Edita elementos del canvas (old_value -> new_value)', category: 'canvas' },
{ name: 'canvas_css', description: 'Inyecta CSS en el canvas', category: 'canvas' }, { name: 'canvas_css', description: 'Inyecta CSS en el canvas', category: 'canvas' },
{ name: 'canvas_js', description: 'Ejecuta JavaScript en el canvas', category: 'canvas' }, { name: 'canvas_js', description: 'Ejecuta JavaScript en el canvas', category: 'canvas' },
{ name: 'get_canvas_css', description: 'Obtiene CSS inyectado en el canvas', category: 'canvas' }, { name: 'get_canvas_css', description: 'Obtiene CSS inyectado', category: 'canvas' },
{ name: 'save_canvas_snapshot', description: 'Guarda el estado actual del canvas como snapshot', category: 'canvas' }, { name: 'save_canvas_snapshot', description: 'Guarda el estado actual del canvas como snapshot', category: 'canvas' },
{ name: 'load_canvas_snapshot', description: 'Restaura un snapshot del canvas', category: 'canvas' }, { name: 'load_canvas_snapshot', description: 'Restaura un snapshot del canvas', category: 'canvas' },
{ name: 'list_canvas_snapshots', description: 'Lista snapshots del canvas guardados', category: 'canvas' }, { name: 'list_canvas_snapshots', description: 'Lista snapshots del canvas guardados', category: 'canvas' },