From 11bc39393b57af540c4d8794192b52b282093b26 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Thu, 30 Apr 2026 13:32:11 -0700 Subject: [PATCH] Add service catalog tool renderer --- .../tools/__tests__/gravity-index.test.ts | 49 +++++++++++++++ cli/src/components/tools/gravity-index.tsx | 61 +++++++++++++++++++ cli/src/components/tools/registry.ts | 2 + 3 files changed, 112 insertions(+) create mode 100644 cli/src/components/tools/__tests__/gravity-index.test.ts create mode 100644 cli/src/components/tools/gravity-index.tsx diff --git a/cli/src/components/tools/__tests__/gravity-index.test.ts b/cli/src/components/tools/__tests__/gravity-index.test.ts new file mode 100644 index 0000000000..91bb9893c0 --- /dev/null +++ b/cli/src/components/tools/__tests__/gravity-index.test.ts @@ -0,0 +1,49 @@ +import { describe, expect, test } from 'bun:test' + +import { getGravityIndexDescription } from '../gravity-index' + +describe('getGravityIndexDescription', () => { + test('describes search queries', () => { + expect( + getGravityIndexDescription({ + action: 'search', + query: 'transactional email for a Next.js app', + }), + ).toBe('Searching transactional email for a Next.js app') + }) + + test('describes browse category and keyword', () => { + expect( + getGravityIndexDescription({ + action: 'browse', + category: 'Email', + q: 'send', + }), + ).toBe('Browsing Email for send') + }) + + test('describes service detail lookups', () => { + expect( + getGravityIndexDescription({ + action: 'get_service', + slug: 'sendgrid', + }), + ).toBe('Getting sendgrid') + }) + + test('describes completed integration reports', () => { + expect( + getGravityIndexDescription({ + action: 'report_integration', + integrated_slug: 'sendgrid', + }), + ).toBe('Reporting sendgrid integration') + }) + + test('uses fallback text for unknown input', () => { + expect(getGravityIndexDescription({ action: 'unknown' })).toBe( + 'Using service catalog', + ) + expect(getGravityIndexDescription(null)).toBe('Using service catalog') + }) +}) diff --git a/cli/src/components/tools/gravity-index.tsx b/cli/src/components/tools/gravity-index.tsx new file mode 100644 index 0000000000..ff3bfb5732 --- /dev/null +++ b/cli/src/components/tools/gravity-index.tsx @@ -0,0 +1,61 @@ +import { SimpleToolCallItem } from './tool-call-item' +import { defineToolComponent } from './types' + +import type { ToolRenderConfig } from './types' + +const asTrimmedString = (value: unknown): string => + typeof value === 'string' ? value.trim() : '' + +export const getGravityIndexDescription = (input: unknown): string => { + if (!input || typeof input !== 'object') { + return 'Using service catalog' + } + + const params = input as Record + const action = asTrimmedString(params.action) + + switch (action) { + case 'search': { + const query = asTrimmedString(params.query) + return query ? `Searching ${query}` : 'Searching services' + } + case 'browse': { + const category = asTrimmedString(params.category) + const query = asTrimmedString(params.q) + return ['Browsing', category || 'services', query ? `for ${query}` : ''] + .filter(Boolean) + .join(' ') + } + case 'list_categories': + return 'Listing service categories' + case 'get_service': { + const slug = asTrimmedString(params.slug) + return slug ? `Getting ${slug}` : 'Getting service details' + } + case 'report_integration': { + const slug = asTrimmedString(params.integrated_slug) + return slug ? `Reporting ${slug} integration` : 'Reporting integration' + } + default: + return 'Using service catalog' + } +} + +/** + * UI component for gravity_index. + * Displays a one-line summary of what Gravity Index is searching or doing. + */ +export const GravityIndexComponent = defineToolComponent({ + toolName: 'gravity_index', + + render(toolBlock): ToolRenderConfig { + return { + content: ( + + ), + } + }, +}) diff --git a/cli/src/components/tools/registry.ts b/cli/src/components/tools/registry.ts index 11bbafe802..df5a2590c6 100644 --- a/cli/src/components/tools/registry.ts +++ b/cli/src/components/tools/registry.ts @@ -1,6 +1,7 @@ import { ApplyPatchComponent } from './apply-patch' import { CodeSearchComponent } from './code-search' import { GlobComponent } from './glob' +import { GravityIndexComponent } from './gravity-index' import { ListDirectoryComponent } from './list-directory' import { ReadDocsComponent } from './read-docs' import { ReadFilesComponent } from './read-files' @@ -30,6 +31,7 @@ const toolComponentRegistry = new Map([ [ApplyPatchComponent.toolName, ApplyPatchComponent], [CodeSearchComponent.toolName, CodeSearchComponent], [GlobComponent.toolName, GlobComponent], + [GravityIndexComponent.toolName, GravityIndexComponent], [ListDirectoryComponent.toolName, ListDirectoryComponent], [RunTerminalCommandComponent.toolName, RunTerminalCommandComponent], [ReadDocsComponent.toolName, ReadDocsComponent],