Checkpoint

This commit is contained in:
Siddharth Ganesan
2025-07-08 21:47:30 -07:00
parent cc249c2dd0
commit aa343fb62f
7 changed files with 195 additions and 82 deletions

View File

@@ -1,58 +1,37 @@
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { searchDocumentation } from '@/lib/copilot/service'
import { NextRequest, NextResponse } from 'next/server'
import { createLogger } from '@/lib/logs/console-logger'
import { searchDocumentation } from '@/lib/copilot/service'
const logger = createLogger('DocsSearchAPI')
const SearchSchema = z.object({
query: z.string().min(1, 'Query is required'),
topK: z.number().min(1).max(20).default(5),
})
/**
* POST /api/docs/search
* Search documentation for copilot tools
*/
export async function POST(req: NextRequest) {
const requestId = crypto.randomUUID()
export async function POST(request: NextRequest) {
try {
const body = await req.json()
const { query, topK } = SearchSchema.parse(body)
const { query, topK = 5 } = await request.json()
logger.info(`[${requestId}] Documentation search request: "${query}"`, { topK })
if (!query) {
return NextResponse.json({ error: 'Query is required' }, { status: 400 })
}
logger.info('Executing documentation search', { query, topK })
const results = await searchDocumentation(query, { topK })
logger.info(`[${requestId}] Found ${results.length} documentation results`, { query })
logger.info(`Found ${results.length} documentation results`, { query })
return NextResponse.json({
success: true,
results,
query,
totalResults: results.length,
metadata: {
requestId,
query,
topK,
},
})
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Invalid request data', details: error.errors },
{ status: 400 }
)
}
logger.error(`[${requestId}] Documentation search error:`, error)
logger.error('Documentation search API failed', error)
return NextResponse.json(
{
error: 'Failed to search documentation',
details: error instanceof Error ? error.message : 'Unknown error',
success: false,
error: `Documentation search failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
{ status: 500 }
)
}
}
}

View File

@@ -0,0 +1,56 @@
import { NextRequest, NextResponse } from 'next/server'
import { createLogger } from '@/lib/logs/console-logger'
import { useWorkflowYamlStore } from '@/stores/workflows/yaml/store'
const logger = createLogger('GetWorkflowYamlAPI')
export async function POST(request: NextRequest) {
try {
const { includeMetadata = false } = await request.json()
logger.info('Executing get user workflow', { includeMetadata })
// Get the workflow YAML using the same store as the UI
const yamlStore = useWorkflowYamlStore.getState()
const yamlContent = yamlStore.getYaml()
if (!yamlContent) {
return NextResponse.json(
{ success: false, error: 'No workflow content available' },
{ status: 404 }
)
}
let metadata = undefined
if (includeMetadata) {
// Get additional workflow metadata if requested
const workflowStore = yamlStore as any // Access internal state
metadata = {
name: workflowStore.workflow?.name || 'Unnamed Workflow',
description: workflowStore.workflow?.description || '',
createdAt: workflowStore.workflow?.createdAt,
updatedAt: workflowStore.workflow?.updatedAt,
}
}
logger.info('Successfully generated workflow YAML', {
includeMetadata,
yamlLength: yamlContent.length
})
return NextResponse.json({
success: true,
yaml: yamlContent,
metadata: metadata,
})
} catch (error) {
logger.error('Get user workflow API failed', error)
return NextResponse.json(
{
success: false,
error: `Failed to get user workflow: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
{ status: 500 }
)
}
}

View File

@@ -406,7 +406,7 @@ export async function generateChatResponse(
content: message,
})
// Define the documentation search tool for the LLM
// Define the tools available to the LLM
const tools: ProviderToolConfig[] = [
{
id: 'docs_search_internal',
@@ -430,6 +430,24 @@ export async function generateChatResponse(
required: ['query'],
},
},
{
id: 'get_user_workflow',
name: 'Get User Workflow',
description:
'Get the current user workflow as YAML format. This shows all blocks, their configurations, inputs, and connections in the workflow.',
params: {},
parameters: {
type: 'object',
properties: {
includeMetadata: {
type: 'boolean',
description: 'Whether to include additional metadata about the workflow (default: false)',
default: false,
},
},
required: [],
},
},
]
const response = await executeProviderRequest(provider, {

View File

@@ -72,9 +72,77 @@ const docsSearchTool: CopilotTool = {
},
}
// Get user workflow as YAML tool for copilot
const getUserWorkflowTool: CopilotTool = {
id: 'get_user_workflow',
name: 'Get User Workflow',
description:
'Get the current user workflow as YAML format. This shows all blocks, their configurations, inputs, and connections in the workflow.',
parameters: {
type: 'object',
properties: {
includeMetadata: {
type: 'boolean',
description: 'Whether to include additional metadata about the workflow (default: false)',
default: false,
},
},
required: [],
},
execute: async (args: Record<string, any>): Promise<CopilotToolResult> => {
try {
const { includeMetadata = false } = args
logger.info('Executing get user workflow', { includeMetadata })
// Import the workflow YAML store dynamically to avoid import issues
const { useWorkflowYamlStore } = await import('@/stores/workflows/yaml/store')
const { useWorkflowRegistry } = await import('@/stores/workflows/registry/store')
// Get the current workflow YAML
const yamlContent = useWorkflowYamlStore.getState().getYaml()
// Get additional metadata if requested
let metadata = {}
if (includeMetadata) {
const registry = useWorkflowRegistry.getState()
const activeWorkflowId = registry.activeWorkflowId
const activeWorkflow = activeWorkflowId ? registry.workflows[activeWorkflowId] : null
if (activeWorkflow) {
metadata = {
workflowId: activeWorkflowId,
name: activeWorkflow.name,
description: activeWorkflow.description,
lastModified: activeWorkflow.lastModified,
workspaceId: activeWorkflow.workspaceId,
}
}
}
logger.info('Successfully retrieved user workflow YAML')
return {
success: true,
data: {
yaml: yamlContent,
metadata: includeMetadata ? metadata : undefined,
},
}
} catch (error) {
logger.error('Get user workflow failed', error)
return {
success: false,
error: `Failed to get user workflow: ${error instanceof Error ? error.message : 'Unknown error'}`,
}
}
},
}
// Copilot tools registry
const copilotTools: Record<string, CopilotTool> = {
docs_search_internal: docsSearchTool,
get_user_workflow: getUserWorkflowTool,
}
// Get a copilot tool by ID

View File

@@ -1,23 +1,6 @@
import type { ToolConfig } from '../types'
export interface DocsSearchParams {
query: string
topK?: number
}
export interface DocsSearchResponse {
results: Array<{
id: number
title: string
url: string
content: string
similarity: number
}>
query: string
totalResults: number
}
export const docsSearchTool: ToolConfig<DocsSearchParams, DocsSearchResponse> = {
export const docsSearchTool: ToolConfig = {
id: 'docs_search_internal',
name: 'Search Documentation',
description:
@@ -34,7 +17,6 @@ export const docsSearchTool: ToolConfig<DocsSearchParams, DocsSearchResponse> =
type: 'number',
required: false,
description: 'Number of results to return (default: 5, max: 10)',
default: 5,
},
},
@@ -50,25 +32,4 @@ export const docsSearchTool: ToolConfig<DocsSearchParams, DocsSearchResponse> =
}),
isInternalRoute: true,
},
transformResponse: async (response: Response): Promise<any> => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
output: {},
error: data.error || 'Failed to search documentation',
}
}
return {
success: true,
output: {
results: data.results || [],
query: data.query || '',
totalResults: data.totalResults || 0,
},
}
},
}
}

View File

@@ -4,10 +4,17 @@ import { useCustomToolsStore } from '@/stores/custom-tools/store'
import { useEnvironmentStore } from '@/stores/settings/environment/store'
import { docsSearchTool } from './docs/search'
import { tools } from './registry'
import { getUserWorkflowTool } from './workflow/get-yaml'
import type { TableRow, ToolConfig, ToolResponse } from './types'
const logger = createLogger('ToolsUtils')
// Internal-only tools (not exposed to users in workflows)
const internalTools: Record<string, ToolConfig> = {
docs_search_internal: docsSearchTool,
get_user_workflow: getUserWorkflowTool,
}
/**
* Transforms a table from the store format to a key-value object
* @param table Array of table rows from the store
@@ -268,11 +275,6 @@ export function createCustomToolRequestBody(
}
}
// Internal-only tools (not exposed to users in workflows)
const internalTools: Record<string, ToolConfig> = {
docs_search_internal: docsSearchTool,
}
// Get a tool by its ID
export function getTool(toolId: string): ToolConfig | undefined {
// Check for internal tools first

View File

@@ -0,0 +1,29 @@
import type { ToolConfig } from '../types'
export const getUserWorkflowTool: ToolConfig = {
id: 'get_user_workflow',
name: 'Get User Workflow',
description:
'Get the current user workflow as YAML format. This shows all blocks, their configurations, inputs, and connections in the workflow.',
version: '1.0.0',
params: {
includeMetadata: {
type: 'boolean',
required: false,
description: 'Whether to include additional metadata about the workflow (default: false)',
},
},
request: {
url: '/api/workflows/current/yaml',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
includeMetadata: params.includeMetadata || false,
}),
isInternalRoute: true,
},
}