| name | fastgpt-sdk-factory |
| description | Use when creating, reviewing, or modifying FastGPT Tool Plugins with the @fastgpt-plugin/sdk-factory TypeScript SDK, including defineTool, defineToolSet, createToolHandler, Zod input/output schemas, secretSchema, ctx.invoke host calls, and streaming tool responses. |
FastGPT SDK Factory
Use this skill when working on a FastGPT Tool Plugin that imports @fastgpt-plugin/sdk-factory or the local sdk/factory package.
Core Pattern
Plugin entry files default-export the instance returned by defineTool() or defineToolSet().
import {
createToolHandler,
defineTool,
type InputSchemaMetaType,
type OutputSchemaMetaType
} from '@fastgpt-plugin/sdk-factory';
import z from 'zod';
const handler = createToolHandler({
inputSchema: z.object({
text: z.string().meta({
title: 'Text'
} satisfies InputSchemaMetaType)
}),
outputSchema: z.object({
result: z.string().meta({
title: 'Result'
} satisfies OutputSchemaMetaType)
}),
handler: async (input) => ({
result: input.text.toUpperCase()
})
});
export default defineTool({
manifest: {
pluginId: 'uppercase',
version: '1.0.0',
name: {
en: 'Uppercase',
'zh-CN': '转大写'
},
description: {
en: 'Convert text to uppercase',
'zh-CN': '将文本转换为大写'
},
versionDescription: {
en: 'Initial version',
'zh-CN': '初始版本'
},
tags: ['tools']
},
handler
});
Handler Rules
- Define handlers with
createToolHandler({ inputSchema, outputSchema, secretSchema?, handler }).
- Use
z.object(...) for inputSchema and outputSchema so TypeScript can infer input and return types.
- Import
InputSchemaMetaType, OutputSchemaMetaType, and SecretSchemaMetaType from @fastgpt-plugin/sdk-factory when schema metadata is used.
- Add
.meta({ ... } satisfies InputSchemaMetaType) to input fields and .meta({ ... } satisfies OutputSchemaMetaType) to output fields that need UI/manifest metadata.
- Set
toolDescription in an input field's .meta() when that field should be available as an automatically filled tool-call parameter; without toolDescription, users must specify the field manually.
- Add
.meta({ isSecret: true | false, ... } satisfies SecretSchemaMetaType) to every secretSchema field; set isSecret: true for values that must be encrypted at rest.
- Return an object that matches
outputSchema; throw errors for failed operations.
- Add
secretSchema when plugin configuration needs secrets such as API keys.
- Read secrets from
ctx.secrets; the value is typed from secretSchema.
- Use
ctx.streamResponse({ type: 'answer', content }) to emit incremental visible output before the final response.
- Use
ctx.systemVar only for FastGPT-provided runtime variables.
const secretSchema = z.object({
apiKey: z.string().meta({
title: 'API Key',
isSecret: true
} satisfies SecretSchemaMetaType)
});
const handler = createToolHandler({
inputSchema: z.object({
query: z.string().meta({
title: 'Query',
toolDescription: 'Search query'
} satisfies InputSchemaMetaType)
}),
outputSchema: z.object({
answer: z.string().meta({
title: 'Answer'
} satisfies OutputSchemaMetaType)
}),
secretSchema,
handler: async (input, ctx) => {
ctx.streamResponse({
type: 'answer',
content: `Searching: ${input.query}`
});
return {
answer: `Result for ${input.query}`
};
}
});
Manifest Rules
manifest must include these fields unless the surrounding package already supplies them:
pluginId: stable unique plugin id.
version: plugin version, usually semver.
name: i18n object shaped as { en, 'zh-CN' }.
description: i18n object shaped as { en, 'zh-CN' }.
Common optional fields:
versionDescription
author
repoUrl
tutorialUrl
tags
permission
icon
toolDescription
Use permission to declare host capabilities required by the plugin. It is an array of permission strings. Declare only the minimum permissions that the plugin actually uses. When using ctx.invoke to call host capabilities, declare the matching permission.
Supported permissions:
userInfo:read: read user information, for example through ctx.invoke.userInfo().
teamInfo:read: read team information.
model:read: read model information.
dataset:read: read dataset information.
file-upload:allow: upload files, for example through ctx.invoke.uploadFile().
Keep pluginId, child tool id, input field names, and output field names stable for compatibility.
Tool Sets
Use defineToolSet() for one plugin with multiple child tools. Put shared metadata in the top-level manifest; put each child tool's id, name, description, optional icon, optional toolDescription, and handler in children.
import {
createToolHandler,
defineToolSet,
type InputSchemaMetaType,
type OutputSchemaMetaType,
type SecretSchemaMetaType
} from '@fastgpt-plugin/sdk-factory';
import z from 'zod';
const secretSchema = z.object({
apiKey: z.string().meta({
title: 'API Key',
isSecret: true
} satisfies SecretSchemaMetaType)
});
const searchHandler = createToolHandler({
inputSchema: z.object({
query: z.string().meta({
title: 'Query'
} satisfies InputSchemaMetaType)
}),
outputSchema: z.object({
items: z.array(z.string()).meta({
title: 'Items'
} satisfies OutputSchemaMetaType)
}),
secretSchema,
handler: async (input) => ({ items: [input.query] })
});
export default defineToolSet({
secretSchema,
manifest: {
pluginId: 'text-tools',
version: '1.0.0',
name: {
en: 'Text Tools',
'zh-CN': '文本工具集'
},
description: {
en: 'Search and summarize text',
'zh-CN': '搜索和总结文本'
}
},
children: [
{
id: 'search',
name: {
en: 'Search',
'zh-CN': '搜索'
},
description: {
en: 'Search text',
'zh-CN': '搜索文本'
},
toolDescription: 'Search text by query',
handler: searchHandler
}
]
});
Host Invocation
Use ctx.invoke for host capabilities. The SDK exposes userInfo() and uploadFile(). Declare the corresponding manifest.permission item before using a host capability; for example, ctx.invoke.uploadFile() requires file-upload:allow. These methods return a Result tuple shaped as [result, err]; check err before using result. When err is present, throw or return that original err so host-side error details are preserved.
const uploadHandler = createToolHandler({
inputSchema: z.object({
content: z.string().meta({
title: 'Content'
} satisfies InputSchemaMetaType)
}),
outputSchema: z.object({
accessURL: z.string().meta({
title: 'Access URL'
} satisfies OutputSchemaMetaType),
fileName: z.string().meta({
title: 'File Name'
} satisfies OutputSchemaMetaType),
size: z.number().meta({
title: 'Size'
} satisfies OutputSchemaMetaType)
}),
handler: async (input, { invoke }) => {
const [result, err] = await invoke.uploadFile({
fileName: 'result.txt',
contentType: 'text/plain',
file: Buffer.from(input.content, 'utf-8')
});
if (err) {
throw err;
}
if (!result) {
throw new Error('Failed to upload file');
}
return {
accessURL: result.accessURL,
fileName: result.fileName,
size: result.size
};
}
});
Local Development
- In external plugins, import from
@fastgpt-plugin/sdk-factory.
- Inside this monorepo package tests or fixtures, imports may point at
sdk/factory/src or ../../src/index when matching existing local patterns.
- Build the SDK with
pnpm --filter @fastgpt-plugin/sdk-factory build.
- When changing SDK behavior, check
sdk/factory/src/index.ts, sdk/factory/src/tool-factory.ts, sdk/factory/src/invoke.client.ts, and fixtures under sdk/factory/test/fixtures/.