feat (acp): exposed available tools in acp schema (#10097)

This commit is contained in:
Lifei Zhou
2026-06-30 15:43:08 +10:00
committed by GitHub
parent d43c692127
commit 2084c43476
15 changed files with 543 additions and 40 deletions
@@ -157,6 +157,34 @@ describe('Extension Utils', () => {
});
});
it('should preserve available tools metadata', () => {
const extension: FixedExtensionEntry = {
type: 'builtin',
name: 'developer',
description: 'developer',
enabled: true,
available_tools: ['shell', 'read_file'],
};
const formData = extensionToFormData(extension);
expect(formData.available_tools).toEqual(['shell', 'read_file']);
});
it('should omit empty available tools metadata', () => {
const extension: FixedExtensionEntry = {
type: 'builtin',
name: 'developer',
description: 'developer',
enabled: true,
available_tools: [],
};
const formData = extensionToFormData(extension);
expect(formData).not.toHaveProperty('available_tools');
});
it('should not escape @ in command args', () => {
const extension: FixedExtensionEntry = {
type: 'stdio',
@@ -320,6 +348,73 @@ describe('Extension Utils', () => {
timeout: 300,
});
});
it('should create sse extension config', () => {
const formData = {
name: 'test-sse',
description: 'Test SSE extension',
type: 'sse' as const,
cmd: '',
endpoint: 'http://api.example.com/sse',
enabled: true,
timeout: 300,
envVars: [],
headers: [],
};
const config = createExtensionConfig(formData);
expect(config).toEqual({
type: 'sse',
name: 'test-sse',
description: 'Test SSE extension',
uri: 'http://api.example.com/sse',
});
});
it('should preserve available tools metadata', () => {
const formData = {
name: 'developer',
description: 'developer',
type: 'builtin' as const,
cmd: '',
endpoint: '',
enabled: true,
timeout: 300,
envVars: [],
headers: [],
available_tools: ['shell', 'read_file'],
};
const config = createExtensionConfig(formData);
expect(config).toEqual({
type: 'builtin',
name: 'developer',
description: 'developer',
timeout: 300,
available_tools: ['shell', 'read_file'],
});
});
it('should omit empty available tools metadata', () => {
const formData = {
name: 'developer',
description: 'developer',
type: 'builtin' as const,
cmd: '',
endpoint: '',
enabled: true,
timeout: 300,
envVars: [],
headers: [],
available_tools: [],
};
const config = createExtensionConfig(formData);
expect(config).not.toHaveProperty('available_tools');
});
});
describe('splitCmdAndArgs', () => {
@@ -38,6 +38,7 @@ export interface ExtensionFormData {
isEdited?: boolean;
}[];
installation_notes?: string;
available_tools?: string[];
}
export function getDefaultFormData(): ExtensionFormData {
@@ -95,6 +96,11 @@ export function extensionToFormData(extension: FixedExtensionEntry): ExtensionFo
);
}
const availableTools =
'available_tools' in extension
? availableToolsOrUndefined(extension.available_tools)
: undefined;
return {
name: extension.name || '',
description: extension.description || '',
@@ -116,9 +122,19 @@ export function extensionToFormData(extension: FixedExtensionEntry): ExtensionFo
installation_notes: (extension as Record<string, unknown>)['installation_notes'] as
| string
| undefined,
...(availableTools ? { available_tools: availableTools } : {}),
};
}
function availableToolsOrUndefined(availableTools?: string[] | null): string[] | undefined {
return availableTools && availableTools.length > 0 ? availableTools : undefined;
}
function availableToolsConfig(availableTools?: string[] | null) {
const normalized = availableToolsOrUndefined(availableTools);
return normalized ? { available_tools: normalized } : undefined;
}
export function createExtensionConfig(formData: ExtensionFormData): ExtensionConfig {
// Extract just the keys from env vars
const env_keys = formData.envVars.map(({ key }) => key).filter((key) => key.length > 0);
@@ -135,6 +151,7 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
args: args,
timeout: formData.timeout,
...(env_keys.length > 0 ? { env_keys } : {}),
...availableToolsConfig(formData.available_tools),
};
} else if (formData.type === 'streamable_http') {
// Extract headers
@@ -156,14 +173,22 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
uri: formData.endpoint || '',
...(env_keys.length > 0 ? { env_keys } : {}),
headers,
...availableToolsConfig(formData.available_tools),
};
} else {
// For other types
} else if (formData.type === 'builtin') {
return {
type: formData.type,
name: formData.name,
description: formData.description,
timeout: formData.timeout,
...availableToolsConfig(formData.available_tools),
};
} else {
return {
type: formData.type,
name: formData.name,
description: formData.description,
uri: formData.endpoint || '',
};
}
}