Skip to content

Commit

Permalink
feat(tools): update OpenAPI tools (#157)
Browse files Browse the repository at this point in the history
Signed-off-by: Lukáš Janeček <lukas.janecek1@ibm.com>
Co-authored-by: Lukáš Janeček <lukas.janecek1@ibm.com>
  • Loading branch information
xjacka and Lukáš Janeček authored Jan 17, 2025
1 parent 7155c6f commit 1feb69e
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/administration/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
2 changes: 1 addition & 1 deletion src/runs/execution/tools/api-call-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class ApiCallTool extends Tool<StringToolOutput, ApiCallToolOptions> {
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
Expand Down
1 change: 1 addition & 0 deletions src/tools/dtos/tool-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions src/tools/dtos/tool-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export const toolUpdateBodySchema = {
open_api_schema: {
type: 'string'
},
api_key: {
type: 'string'
},
metadata: metadataSchema,
user_description: { type: 'string' }
}
Expand Down
4 changes: 4 additions & 0 deletions src/tools/dtos/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export const toolSchema = {
type: 'string',
nullable: true
},
api_key: {
type: 'string',
nullable: true
},
created_at: {
type: 'number'
},
Expand Down
38 changes: 37 additions & 1 deletion src/tools/tools.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<FrameworkTool, 'description' | 'name' | 'inputSchema'> & {
type: ToolType;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -715,9 +719,31 @@ async function createOpenApiTool(
body: Extract<ToolCreateBody, { open_api_schema: string }>
): Promise<ToolCreateResponse> {
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,
Expand Down Expand Up @@ -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({
Expand Down

0 comments on commit 1feb69e

Please sign in to comment.