Activepieces 属性类型(Property Types)完全指南:从基础输入到动态属性与联动下拉
【免费下载链接】activepiecesAI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces
Activepieces 的每个 action 与 trigger 都通过props声明自己的输入表单,这些属性类型同时服务于两类使用者:构建器界面中的真人用户,以及通过 MCP 协议接入的 LLM Agent。本指南以.agents/skills/piece-builder/props-patterns.md为骨架,结合packages/pieces/framework源码与packages/pieces/community/github真实实现,系统讲解Property.ShortText、Property.Dropdown、Property.DynamicProperties等全部属性类型的语法、底层机制与实战模式。读完你将能够为任意第三方 API 设计出既符合类型约束、又能被 LLM 准确理解的属性表单。
属性描述(description)是 Agent 的唯一信号
description是 LLM/MCP Agent(以及构建器中的用户)决定如何填写属性的唯一依据,它应该是一两句「规格说明」,而不是一个标签:
- 说明格式,而不仅是概念。
"Issue title. Max 255 characters."远胜于"The title"。 - 当格式重要时,把真实的样例直接写进描述文案。例如真实的 ID 形态(
'cus_abc123xyz')、ISO 8601 日期('2026-04-17T10:30:00Z')、带协议头的完整 URL。属性体系中没有单独的 example 字段,description 承担了全部信号,例如:"Current status of the record. One of: 'open', 'in_progress', 'closed'."。 - 当属性不言自明时可跳过样例(如布尔复选框),或者值来自运行时 API(
Property.Dropdown、Property.DynamicProperties)。 - 绝不使用占位符式的空样例——
'string'、'value'、'<your API key>'、空的{}/[]都毫无信息量。
这条规则在 .agents/skills/piece-builder/SKILL.md 的「UX Quality」一节得到呼应:pieces 的使用者可能是从未接触过 API 的人,描述必须具有教学性,例如不要写「输入线程时间戳」,而要写「点击消息右侧的三个点,选择 Copy Link,粘贴末尾的数字」。
文本、数字与布尔:基础标量类型
最常用的三个基础类型,语法与用途如下:
Property.ShortText({ displayName: 'Title', description: 'Optional help text', required: true, defaultValue: 'Default text', }) Property.LongText({ displayName: 'Body', required: false, })ShortText对应单行输入,适合姓名、邮箱、ID 等短值;LongText对应多行文本域,适合备注、正文等自由长文本;Number接收数值;Checkbox接收布尔值:
Property.Number({ displayName: 'Limit', required: false, defaultValue: 10, }) Property.Checkbox({ displayName: 'Include archived?', required: false, defaultValue: false, })在源码层面,这些类型分别对应 text-property.ts、number-property.ts 与 checkbox-property.ts,它们共享 common.ts 中的BasePropertySchema(包含displayName、description、required、defaultValue等公共字段)。
日期时间与文件
Property.DateTime({ displayName: 'Due Date', required: false, }) Property.File({ displayName: 'Attachment', required: false, })DateTime表示一个时间瞬间(对应 date-time-property.ts);File在运行时解析为ApFile对象(见 file-property.ts)。如果需要「时间窗口」(如最近 7 天),应改用Property.DateRange,在run()中通过dateRangeUtils.resolve(context.propsValue.date_range)解析出{ after, before }ISO 字符串——这是搜索/筛选类 action 的标准做法,详见 property-ui-selection.md 的显示增强章节。
JSON、Object 与 Array
结构化数据的三种形态:
Property.Json({ displayName: 'Custom Data', description: 'Enter valid JSON', required: false, }) Property.Object({ displayName: 'Metadata', description: 'Key-value pairs', required: false, }) // Simple array of strings Property.Array({ displayName: 'Tags', required: false, }) // Array with structured sub-properties Property.Array({ displayName: 'Line Items', required: true, properties: { name: Property.ShortText({ displayName: 'Item Name', required: true }), quantity: Property.Number({ displayName: 'Quantity', required: true }), price: Property.Number({ displayName: 'Price', required: false }), }, })要点:Json只应在没有更好的结构化选项时使用(对应 json-property.ts);Object提供字典编辑器(object-property.ts);Array不带properties时是纯字符串列表(标签、邮箱),带properties时则渲染为可重复的记录编辑器(如订单行项目),底层实现见 array-property.ts。
静态下拉:预定义选项
Property.StaticDropdown({ displayName: 'Status', required: true, options: { options: [ { label: 'Active', value: 'active' }, { label: 'Inactive', value: 'inactive' }, { label: 'Archived', value: 'archived' }, ], }, }) Property.StaticMultiSelectDropdown({ displayName: 'Categories', required: false, options: { options: [ { label: 'Sales', value: 'sales' }, { label: 'Marketing', value: 'marketing' }, ], }, })静态下拉适用于选项在编码期就完全确定的场景,定义于 static-dropdown.ts。对于 2~4 个互斥模式,可以附加display: 'cards'让每个选项以「图标 + 一行说明」的形式呈现;StaticDropdown的defaultValue应设为选项中的某个合法值,以便首屏直接渲染。
动态下拉:从 API 拉取选项
动态下拉是「绝不让用户手输 ID」这一铁律的标准答案——用户按名称选择,值传 ID。完整模式:
Property.Dropdown({ displayName: 'Project', auth: myAppAuth, refreshers: [], // Array of prop names this depends on required: true, options: async ({ auth }) => { if (!auth) { return { disabled: true, options: [], placeholder: 'Please connect your account first' }; } const response = await httpClient.sendRequest<{ data: { id: string; name: string }[] }>({ method: HttpMethod.GET, url: 'https://api.example.com/v1/projects', authentication: { type: AuthenticationType.BEARER_TOKEN, token: auth.secret_text }, }); return { disabled: false, options: response.body.data.map((item) => ({ label: item.name, value: item.id, })), }; }, })两条必须遵守的硬规则
始终传
auth。每一个Property.Dropdown、Property.MultiSelectDropdown和Property.DynamicProperties,只要其options/props回调读取了auth,就必须设置auth: <pieceAuth>(例如auth: myAppAuth)。否则回调里的auth是undefined,下拉永远加载不出来。从src/lib/*相对路径导入 auth 对象(import { myAppAuth } from '../auth'),绝不要从src/index.ts的再导出导入。真实范式见 github/src/lib/common/index.ts。
无需类型断言——
auth已自动推断类型。设置auth: myAppAuth一举两得:既让回调拿到auth,又告诉 TypeScript 连接类型。框架仅用该auth字段推断类型,因此回调内auth.secret_text(SecretText)、auth.access_token(OAuth2)、auth.props.<field>(CustomAuth)都是正确类型,直接读取即可。永远不要写auth as { secret_text: string }之类的断言——仓库明令禁止,且纯属冗余。无断言的真实案例见airtable、baremetrics、todoist的 common 文件。
源码层面,auth字段被明确注释为「用于推断 PieceAuth 类型的 dummy 属性」,见 dropdown-prop.ts 与 dynamic-prop.ts。
联动下拉:父属性变化时刷新
当某个下拉的选项依赖另一个属性的值(如先选项目、再选项目下的任务)时,使用refreshers声明依赖:
Property.Dropdown({ displayName: 'Task', refreshers: ['project'], // Re-fetches when 'project' prop changes required: true, auth: myAppAuth, options: async ({ auth, project }) => { if (!auth || !project) { return { disabled: true, options: [], placeholder: 'Please select a project first' }; } const response = await httpClient.sendRequest<{ data: { id: string; name: string }[] }>({ method: HttpMethod.GET, url: `https://api.example.com/v1/projects/${project}/tasks`, authentication: { type: AuthenticationType.BEARER_TOKEN, token: auth.secret_text }, }); return { disabled: false, options: response.body.data.map((item) => ({ label: item.name, value: item.id })), }; }, })refreshers: ['project']表示当名为project的属性变化时重新执行options回调,回调参数中会带上该项目名对应的当前值。前置条件未满足时返回disabled: true并给出有引导性的placeholder(「Please select a project first」而非留空)。真实实现可查看 GitHub piece 的repositoryDropdown、issueDropdown、labelDropDown——它们正是「仓库 → 议题 → 标签」三级联动的范例,见 github/src/lib/common/index.ts。
动态多选下拉
Property.MultiSelectDropdown({ displayName: 'Labels', refreshers: ['repository'], required: false, auth:myAppAuth, options: async ({ auth, repository }) => { // Same pattern as Dropdown, returns multiple selected values }, })模式与Dropdown完全一致,区别在于返回值是多个选中值组成的数组。其类型定义位于 dropdown-prop.ts,TPropertyValue<T[], ...>表明运行时值是一个数组。
动态属性:字段在运行时才确定
当表单字段本身来自 API(例如自定义表格的列)时,用DynamicProperties在运行时构建子表单:
Property.DynamicProperties({ displayName: 'Record Fields', refreshers: ['tableId'], required: true, auth: myAppAuth, props: async ({ auth, tableId }): Promise<DynamicPropsValue> => { if (!auth || !tableId) return {}; const fields = await fetchTableFields(auth, tableId); const properties: DynamicPropsValue = {}; for (const field of fields) { properties[field.id] = Property.ShortText({ displayName: field.name, required: field.required, }); } return properties; }, })底层实现见 dynamic-prop.ts:DynamicPropsValue是Record<string, DynamicProp>,而DynamicProp是ShortText、StaticDropdown、Json、Array、StaticMultiSelectDropdown五种类型的联合(第 11-25 行)——也就是说,动态属性内部可以嵌套这些受限的属性类型。这是最重的组件,只有当字段形态真正依赖运行时数据时才使用。
动态属性作为来源选择器:互斥输入
当用户必须在两种互斥的输入方式之间选择(上传文件 vs S3、URL vs 文件等)时,用「StaticDropdown选择器 +DynamicProperties联动」组合:
source: Property.StaticDropdown({ displayName: 'File Source', description: 'Choose how to provide the file.', required: true, defaultValue: 'file', options: { options: [ { label: 'Upload a file', value: 'file' }, { label: 'From S3 bucket', value: 's3' }, ], }, }), document: Property.DynamicProperties({ auth: myAppAuth, displayName: 'File', required: true, refreshers: ['source'], // IMPORTANT: explicit Promise<DynamicPropsValue> return type is required // for the UI to re-render when the source selector changes. props: async ({ source }): Promise<DynamicPropsValue> => { if (source === 's3') { return { s3Bucket: Property.ShortText({ displayName: 'S3 Bucket', required: true, }), s3Key: Property.ShortText({ displayName: 'S3 File Path', required: true, }), }; } return { file: Property.File({ displayName: 'File', required: true, }), }; }, }),规则清单
- 始终显式声明
Promise<DynamicPropsValue>返回类型——没有它,UI 不会在选择器切换时重新渲染; - 每个分支直接返回对象字面量——不要先构建可变对象再条件赋值;
- 所有分支之后以兜底
return {}结尾; - 直接比较选择器值(
source === 's3')——不需要as unknown as string之类的断言; - 在
StaticDropdown上设置defaultValue,保证首次加载即渲染第一个分支。
在 run() 中读取值
const file = source === 'file' ? document['file'] : undefined; const s3Bucket = source === 's3' ? (document['s3Bucket'] as string) : undefined; const s3Key = source === 's3' ? (document['s3Key'] as string) : undefined;Markdown:纯展示,不收集输入
Property.MarkDown({ value: '## Instructions\n1. Go to Settings\n2. Copy your API key', })用于设置步骤说明、警告信息或 Webhook URL 展示。判断何时使用它,可参考 ux-guidelines.md(复杂设置的 Markdown 引导是 UX 质量规则之一:当某个属性需要在第三方应用里预先配置时,用带编号步骤的Property.MarkDown())。
属性类型的选型与更完整决策树
本指南专注属性类型的「语法」;「该用哪个组件、加什么显示增强、如何分组」的完整决策树见 property-ui-selection.md:包括display: 'cards'/'stepper'、RichText+formatProperty、Checkbox的reveals渐进披露、propertyGroups的tabs/section/builder/footer四种布局,以及合法的icon名称列表。而createPiece({ categories: [...] })所需的PieceCategory取值不属于属性类型范畴,统一收录在 piece-types.md。所有类型的渲染预览可见 docs/build-pieces/piece-reference/properties.mdx。
总结
Activepieces 属性体系以「描述即信号」为设计哲学:每个属性既要在构建器中呈现为可用的输入控件,也要向 LLM Agent 传达填写所需的一切上下文。从静态标量到动态下拉、再到可重渲染的动态属性组合,类型系统通过refreshers、auth推断与DynamicPropsValue的联合约束,在编码期保证了表单的运行时正确性。遵循本指南的规则——传auth、不写断言、显式返回类型、描述含真实样例——即可写出对人和 Agent 都友好、且通过 CI 构建与 lint 的 piece 属性。
【免费下载链接】activepiecesAI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考