Path: blob/main/extensions/copilot/src/extension/byok/common/geminiFunctionDeclarationConverter.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { FunctionDeclaration, Schema, Type } from '@google/genai';67export type ToolJsonSchema = {8type?: string;9description?: string;10properties?: Record<string, ToolJsonSchema>;11items?: ToolJsonSchema;12required?: string[];13enum?: string[];1415// Add support for JSON Schema composition keywords16anyOf?: ToolJsonSchema[];17oneOf?: ToolJsonSchema[];18allOf?: ToolJsonSchema[];19};2021// Map JSON schema types to Gemini Type enum22function mapType(jsonType: string): Type {23switch (jsonType) {24case 'object':25return Type.OBJECT;26case 'array':27return Type.ARRAY;28case 'string':29return Type.STRING;30case 'number':31return Type.NUMBER;32case 'integer':33return Type.INTEGER;34case 'boolean':35return Type.BOOLEAN;36case 'null':37return Type.NULL;38default:39throw new Error(`Unsupported type: ${jsonType}`);40}41}4243// Convert JSON schema → Gemini function declaration44export function toGeminiFunction(name: string, description: string, schema: ToolJsonSchema): FunctionDeclaration {45// If schema root is array, we use its items for function parameters46const target = schema.type === 'array' && schema.items ? schema.items : schema;4748const parameters: Schema = {49type: Type.OBJECT,50properties: transformProperties(target.properties || {}),51required: Array.isArray(target.required) ? target.required : []52};5354return {55name,56description: description || 'No description provided.',57parameters58};59}6061// Recursive transformation for nested properties62function transformProperties(props: Record<string, ToolJsonSchema>): Record<string, any> {63const result: Record<string, any> = {};6465for (const [key, value] of Object.entries(props)) {6667// Handle anyOf, oneOf, allOf by picking the first valid entry68const effectiveValue =69(value.anyOf?.[0] || value.oneOf?.[0] || value.allOf?.[0] || value) as ToolJsonSchema;707172const transformed: any = {73// If type is undefined, throw an error to avoid incorrect assumptions74type: effectiveValue.type75? mapType(effectiveValue.type)76: Type.OBJECT77};7879if (effectiveValue.description) {80transformed.description = effectiveValue.description;81}8283// Enum support84if (effectiveValue.enum) {85transformed.enum = effectiveValue.enum;86}8788if (effectiveValue.type === 'object' && effectiveValue.properties) {89transformed.properties = transformProperties(effectiveValue.properties);90if (effectiveValue.required) {91transformed.required = effectiveValue.required;92}93} else if (effectiveValue.type === 'array' && effectiveValue.items) {94const itemType = effectiveValue.items.type === 'object' ? Type.OBJECT : mapType(effectiveValue.items.type ?? 'object');95const itemSchema: any = { type: itemType };9697if (effectiveValue.items.description) {98itemSchema.description = effectiveValue.items.description;99}100101if (effectiveValue.items.enum) {102itemSchema.enum = effectiveValue.items.enum;103}104105if (effectiveValue.items.properties) {106itemSchema.properties = transformProperties(effectiveValue.items.properties);107if (effectiveValue.items.required) {108itemSchema.required = effectiveValue.items.required;109}110}111112transformed.items = itemSchema;113}114115result[key] = transformed;116}117118return result;119}120121