mirror of
https://github.com/microsoft/vscode.git
synced 2026-08-15 02:07:31 +01:00
Merge pull request #328147 from microsoft/agents/gemini-agent-host-byok-fixes
copilot: preserve Gemini BYOK tool fidelity
This commit is contained in:
@@ -11,7 +11,7 @@ export type ToolJsonSchema = {
|
||||
properties?: Record<string, ToolJsonSchema>;
|
||||
items?: ToolJsonSchema;
|
||||
required?: string[];
|
||||
enum?: string[];
|
||||
enum?: unknown[];
|
||||
|
||||
// Add support for JSON Schema composition keywords
|
||||
anyOf?: ToolJsonSchema[];
|
||||
@@ -104,8 +104,11 @@ function transformConcrete(schema: ToolJsonSchema): Schema {
|
||||
transformed.description = schema.description;
|
||||
}
|
||||
|
||||
if (schema.enum) {
|
||||
transformed.enum = schema.enum;
|
||||
if (type === 'string' && schema.enum) {
|
||||
const values = schema.enum.filter((value): value is string => typeof value === 'string');
|
||||
if (values.length > 0) {
|
||||
transformed.enum = values;
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'object' && schema.properties) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import type { Content, FunctionCall, FunctionResponse, Part } from '@google/genai';
|
||||
import { Raw } from '@vscode/prompt-tsx';
|
||||
import type { LanguageModelChatMessage } from 'vscode';
|
||||
import type { LanguageModelChatMessage, LanguageModelChatMessage2 } from 'vscode';
|
||||
import { CustomDataPartMimeTypes } from '../../../platform/endpoint/common/endpointTypes';
|
||||
import { LanguageModelChatMessageRole, LanguageModelDataPart, LanguageModelTextPart, LanguageModelThinkingPart, LanguageModelToolCallPart, LanguageModelToolResultPart, LanguageModelToolResultPart2 } from '../../../vscodeTypes';
|
||||
|
||||
@@ -120,7 +120,7 @@ function apiContentToGeminiContent(content: (LanguageModelTextPart | LanguageMod
|
||||
return convertedContent;
|
||||
}
|
||||
|
||||
export function apiMessageToGeminiMessage(messages: LanguageModelChatMessage[]): { contents: Content[]; systemInstruction?: Content } {
|
||||
export function apiMessageToGeminiMessage(messages: Array<LanguageModelChatMessage | LanguageModelChatMessage2>): { contents: Content[]; systemInstruction?: Content } {
|
||||
const contents: Content[] = [];
|
||||
let systemInstruction: Content | undefined;
|
||||
|
||||
@@ -131,8 +131,7 @@ export function apiMessageToGeminiMessage(messages: LanguageModelChatMessage[]):
|
||||
if (message.role === LanguageModelChatMessageRole.System) {
|
||||
// Gemini uses system instruction separately
|
||||
const systemText = message.content
|
||||
.filter((p): p is LanguageModelTextPart => p instanceof LanguageModelTextPart)
|
||||
.map(p => p.value)
|
||||
.map(part => part instanceof LanguageModelTextPart ? part.value : '')
|
||||
.join('');
|
||||
|
||||
if (systemText.trim()) {
|
||||
|
||||
+35
@@ -179,6 +179,41 @@ describe('GeminiFunctionDeclarationConverter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should omit non-string enums from nested schemas', () => {
|
||||
const result = toGeminiFunction('nestedEnumFunction', 'Function with nested non-string enums', {
|
||||
type: 'object',
|
||||
properties: {
|
||||
values: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: {
|
||||
type: 'boolean',
|
||||
enum: [true]
|
||||
},
|
||||
count: {
|
||||
type: 'integer',
|
||||
enum: [1, 2]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.parameters!.properties!['values']).toEqual({
|
||||
type: Type.ARRAY,
|
||||
items: {
|
||||
type: Type.OBJECT,
|
||||
properties: {
|
||||
enabled: { type: Type.BOOLEAN },
|
||||
count: { type: Type.INTEGER }
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle nullable anyOf schemas', () => {
|
||||
const result = toGeminiFunction('nullableAnyOfFunction', 'Function with nullable anyOf', {
|
||||
type: 'object',
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
import { Raw } from '@vscode/prompt-tsx';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import type { LanguageModelChatMessage } from 'vscode';
|
||||
import type { LanguageModelChatMessage, LanguageModelChatMessage2 } from 'vscode';
|
||||
import { CustomDataPartMimeTypes } from '../../../../platform/endpoint/common/endpointTypes';
|
||||
import { LanguageModelChatMessageRole, LanguageModelDataPart, LanguageModelTextPart, LanguageModelToolResultPart, LanguageModelTextPart as LMText } from '../../../../vscodeTypes';
|
||||
import { LanguageModelChatMessageRole, LanguageModelDataPart, LanguageModelTextPart, LanguageModelThinkingPart, LanguageModelToolCallPart, LanguageModelToolResultPart, LanguageModelTextPart as LMText } from '../../../../vscodeTypes';
|
||||
import { apiMessageToGeminiMessage } from '../geminiMessageConverter';
|
||||
|
||||
describe('GeminiMessageConverter', () => {
|
||||
@@ -80,6 +80,27 @@ describe('GeminiMessageConverter', () => {
|
||||
expect(result.contents[0].parts![1].text).toBe('Hello!');
|
||||
});
|
||||
|
||||
it('should attach a thought signature to the following function call', () => {
|
||||
const messages: Array<LanguageModelChatMessage | LanguageModelChatMessage2> = [{
|
||||
role: LanguageModelChatMessageRole.Assistant,
|
||||
content: [
|
||||
new LanguageModelThinkingPart('', undefined, { signature: 'thought-signature' }),
|
||||
new LanguageModelToolCallPart('call-1', 'default_api:view', { path: 'README.md' }),
|
||||
],
|
||||
name: undefined,
|
||||
}];
|
||||
|
||||
const result = apiMessageToGeminiMessage(messages);
|
||||
|
||||
expect(result.contents[0].parts).toEqual([{
|
||||
functionCall: {
|
||||
name: 'default_api:view',
|
||||
args: { path: 'README.md' },
|
||||
},
|
||||
thoughtSignature: 'thought-signature',
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should extract functionResponse parts from model message into subsequent user message and prune empty model', () => {
|
||||
// Simulate a model message that (incorrectly) contains only a tool result part
|
||||
const toolResult = new LanguageModelToolResultPart('myTool_12345', [new LanguageModelTextPart('{"foo":"bar"}')]);
|
||||
|
||||
Reference in New Issue
Block a user