diff --git a/src/administration/helpers.ts b/src/administration/helpers.ts index d1f5f47..bd8596f 100644 --- a/src/administration/helpers.ts +++ b/src/administration/helpers.ts @@ -45,3 +45,8 @@ export const redactProjectKeyValue = (key: string) => key.substring(API_KEY_PREFIX.length + 2, key.length - 2), '*'.repeat(key.length - 12) ); + +export const redactKey = (key: string) => + key.length >= 10 + ? key.replace(key.substring(2, key.length - 2), '*'.repeat(10)) + : key[0] + '*'.repeat(13); diff --git a/src/runs/execution/tools/api-call-tool.ts b/src/runs/execution/tools/api-call-tool.ts index 16f9c8b..ea753f8 100644 --- a/src/runs/execution/tools/api-call-tool.ts +++ b/src/runs/execution/tools/api-call-tool.ts @@ -113,7 +113,7 @@ export class ApiCallTool extends Tool { this.apiKey = apiKey; this.description = description ?? 'Use input schema to infer description'; this.openApiSchema = parse(openApiSchema); - if (!this.openApiSchema?.paths) { + if (!this.openApiSchema?.servers) { throw new APIError({ message: `Server is not specified`, code: APIErrorCode.INVALID_INPUT diff --git a/src/tools/dtos/tool-create.ts b/src/tools/dtos/tool-create.ts index 6f6e575..e369caf 100644 --- a/src/tools/dtos/tool-create.ts +++ b/src/tools/dtos/tool-create.ts @@ -37,6 +37,7 @@ export const toolCreateBodySchema = { additionalProperties: false, required: ['open_api_schema'], properties: { + name: { type: 'string' }, open_api_schema: { type: 'string' }, api_key: { type: 'string', writeOnly: true }, metadata: metadataSchema, diff --git a/src/tools/dtos/tool-update.ts b/src/tools/dtos/tool-update.ts index d8facb5..b029934 100644 --- a/src/tools/dtos/tool-update.ts +++ b/src/tools/dtos/tool-update.ts @@ -53,6 +53,9 @@ export const toolUpdateBodySchema = { open_api_schema: { type: 'string' }, + api_key: { + type: 'string' + }, metadata: metadataSchema, user_description: { type: 'string' } } diff --git a/src/tools/dtos/tool.ts b/src/tools/dtos/tool.ts index e37fca9..1adcb21 100644 --- a/src/tools/dtos/tool.ts +++ b/src/tools/dtos/tool.ts @@ -63,6 +63,10 @@ export const toolSchema = { type: 'string', nullable: true }, + api_key: { + type: 'string', + nullable: true + }, created_at: { type: 'number' }, diff --git a/src/tools/tools.service.ts b/src/tools/tools.service.ts index 03905f3..1c3f986 100644 --- a/src/tools/tools.service.ts +++ b/src/tools/tools.service.ts @@ -75,6 +75,8 @@ import { ReadFileTool } from '@/runs/execution/tools/read-file-tool.js'; import { snakeToCamel } from '@/utils/strings.js'; import { createSearchTool } from '@/runs/execution/tools/search-tool'; import { defaultAIProvider } from '@/runs/execution/provider'; +import { redactKey } from '@/administration/helpers.js'; +import decrypt from '@/utils/crypto/decrypt.js'; type SystemTool = Pick & { type: ToolType; @@ -246,6 +248,8 @@ export function toDto(tool: AnyTool | SystemTool): ToolDto { ? JSON.stringify(tool.parameters) : null, open_api_schema: tool.executor === ToolExecutor.API ? tool.openApiSchema : null, + api_key: + tool.executor === ToolExecutor.API && tool.apiKey ? redactKey(decrypt(tool.apiKey)) : null, description: tool.description }; } else { @@ -715,9 +719,31 @@ async function createOpenApiTool( body: Extract ): Promise { const schema = parse(body.open_api_schema); + + if (!schema.info.title && !body.name) { + throw new APIError({ + message: 'Body name or OpenAPI info.name is requred.', + code: APIErrorCode.INVALID_INPUT + }); + } + + if (!schema.info.description) { + throw new APIError({ + message: 'OpenAPI info.description is requred.', + code: APIErrorCode.INVALID_INPUT + }); + } + + if (!schema.servers || schema.servers.length === 0 || !schema.servers[0].url) { + throw new APIError({ + message: 'OpenAPI servers is requred.', + code: APIErrorCode.INVALID_INPUT + }); + } + const tool = new ApiTool({ openApiSchema: body.open_api_schema, - name: schema.info.title, + name: body.name ?? schema.info.title, description: schema.info.description, apiKey: body.api_key ? encrypt(body.api_key) : undefined, metadata: body.metadata, @@ -815,6 +841,16 @@ export async function updateTool({ tool.openApiSchema = getUpdatedValue(body.open_api_schema, tool.openApiSchema); } + if ('api_key' in body) { + if (!('apiKey' in tool)) { + throw new APIError({ + message: 'Can not change tool executor', + code: APIErrorCode.INVALID_INPUT + }); + } + tool.apiKey = getUpdatedValue(body.api_key, tool.apiKey); + } + if ('parameters' in body) { if (!('parameters' in tool)) { throw new APIError({