MCP Terminal Server
by dillip285
- genkit-tools
- common
- src
- plugin
/**
* 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;
}