MCP Terminal Server

/** * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as clc from 'colorette'; import * as fs from 'fs'; import * as path from 'path'; import * as process from 'process'; import { z } from 'zod'; import { TraceDataSchema } from '../types/trace'; import { ToolPluginSchema } from './plugins'; const CONFIG_NAME = 'genkit-tools.conf.js'; export const EVAL_FIELDS = ['input', 'output', 'context'] as const; export type EvalField = (typeof EVAL_FIELDS)[number]; const InputSelectorSchema = z.object({ inputOf: z.string(), }); export type InputStepSelector = z.infer<typeof InputSelectorSchema>; const OutputSelectorSchema = z.object({ outputOf: z.string(), }); export type OutputStepSelector = z.infer<typeof OutputSelectorSchema>; const StepSelectorSchema = z.union([InputSelectorSchema, OutputSelectorSchema]); export type StepSelector = z.infer<typeof StepSelectorSchema>; const EvaluationExtractorSchema = z.record( z.enum(EVAL_FIELDS), z.union([ z.string(), // specify the displayName (default to output) StepSelectorSchema, //, {inputOf: 'my-step-name'} z.function().args(TraceDataSchema).returns(z.any()), // custom trace extractor ]) ); export type EvaluationExtractor = z.infer<typeof EvaluationExtractorSchema>; export function isEvalField(input: string): input is EvalField { const foundField = EVAL_FIELDS.some((v) => v === input); return !!foundField; } const EvaluatorConfig = z.object({ actionRef: z .string() .describe('specify which flow this config is for') .optional(), extractors: EvaluationExtractorSchema, }); const ToolsConfigSchema = z .object({ cliPlugins: z.optional(z.array(ToolPluginSchema)), builder: z .object({ cmd: z.string().optional(), }) .optional(), evaluators: z.array(EvaluatorConfig).optional(), runner: z .object({ mode: z.enum(['default', 'harness']).default('default'), files: z.array(z.string()).optional(), }) .optional(), }) .strict(); export type ToolsConfig = z.infer<typeof ToolsConfigSchema>; let cachedConfig: Promise<ToolsConfig | null> | null = null; /** * Searches recursively up the directory structure for the Genkit tools config * file. */ export async function findToolsConfig(): Promise<ToolsConfig | null> { if (!cachedConfig) { cachedConfig = findToolsConfigInternal(); } return cachedConfig; } async function findToolsConfigInternal(): Promise<ToolsConfig | null> { let current = process.cwd(); while (path.resolve(current, '..') !== current) { if (fs.existsSync(path.resolve(current, CONFIG_NAME))) { const configPath = path.resolve(current, CONFIG_NAME); const config = (await import(configPath)) as { default: unknown }; const result = ToolsConfigSchema.safeParse(config.default); if (result.success) { return result.data; } console.warn( `${clc.bold(clc.yellow('Warning:'))} ` + `Malformed tools schema:\n${result.error.toString()}` ); return null; } current = path.resolve(current, '..'); } return null; } /** * Simply directly returns the tools configuration. We do validation of the * schema at runtime in `findToolsConfig()`. This function is exported for * aesthetic reasons... */ export function genkitToolsConfig(cfg: unknown): ToolsConfig { return cfg as ToolsConfig; }