
Twenty SDK 逻辑函数输入类型推断从 TypeScript 参数到工作流输入表单的完整机制【免费下载链接】twentyThe open alternative to Salesforce, designed for AI.项目地址: https://gitcode.com/GitHub_Trending/tw/twentyTwentyThe open alternative to Salesforce, designed for AI的 SDK 允许开发者用 TypeScript 定义逻辑函数logic function并将其暴露为工作流动作workflow action或 AI 工具AI tool。本文聚焦于一个关键的自动化环节当逻辑函数没有显式声明inputSchema时SDK 如何在 manifest 构建期从 handler 的参数类型推断出输入模式以及TwentyRecord类型如何让“记录型输入”在 workflow builder 中渲染为记录选择器。读完后你将掌握类型推断的映射规则、记录型输入的正确声明方式以及 handler 在运行时真正收到的数据形态。推断的触发时机与总体流程当逻辑函数选择接入工作流动作或 AI 工具表面surface但没有声明显式inputSchema时SDK 会在 manifest build 阶段从 handler 的参数类型推断出输入模式。workflow builder 随后使用该 schema 渲染输入表单其中记录类型record-typed的输入会渲染为记录选择器record picker。从源码结构看这条推断链路的核心实现在 twenty-shared 包中get-input-schema-from-source-code.ts 接收 handler 的源码字符串解析出第一个参数。若第一个参数是带properties的object类型则将其包装为{ type: object, properties: ... }作为最终 schema否则回退到默认的DEFAULT_TOOL_INPUT_SCHEMA。推断结果最终挂载到 manifest 的logicFunctions[].workflowActionTriggerSettings.inputSchema字段上构建入口位于 manifest-build.ts。推断的完整映射规则如下handler 参数属性类型推断出的输入类型说明string/number/boolean对应的标量输入一对一映射字符串字面量联合如a \| bselect 输入联合成员成为可选项T[]/ArrayT数组输入元素类型递归推断TwentyRecordobjectUniversalIdentifier记录输入见下文“记录型输入”需要注意的两个边界条件推断只在 trigger settings 省略inputSchema时运行。一旦你为某个 surface 提供了显式inputSchema该 surface 的推断即被整体禁用——这正是当 handler 类型无法内联表达时的逃生舱escape hatch。推断读取的是 handler 唯一的params对象类型即每个顶层属性都会被映射为一个输入项。记录型输入TwentyRecord 与 universal identifier要把某个输入绑定到工作区中的对象object用TwentyRecord为其标注类型并把该对象的 universal identifier 作为字符串字面量传入。文档给出的完整示例import { defineLogicFunction, type TwentyRecord } from twenty-sdk/define; const handler async (params: { companyId: TwentyRecord20202020-b374-4779-a561-80086cb2e17f; postCardIds: TwentyRecord54b589ca-eeed-4950-a176-358418b85c05[]; }) { return { companyId: params.companyId, postCardCount: params.postCardIds.length, }; };其中companyId是单条记录输入postCardIds是记录数组输入。这两个字面量 identifier 分别对应 Company 标准对象和一个 App 对象PostCard的 universal identifier。universal identifier 从哪里获取标准对象Standard objects从STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS获取它由 twenty-sdk/define 入口 导出同时以别名STANDARD_OBJECT导出例如STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier。App 对象使用你在defineObject(...)上设置的universalIdentifier。关键设计点是universal identifier 是唯一事实来源source of truth直接从字面量读取。不存在任何基于名称的匹配逻辑因此一个无关类型永远不可能被误识别为某个对象上的记录。这也带来一条硬性约束——只有字符串字面量参数才能被解析。不带参数、或参数非字面量的TwentyRecord会被当作未知输入unknown input处理。源码层面对应的类型定义TwentyRecord的定义极其轻量见 twenty-record.type.tsexport type TwentyRecordTObjectUniversalIdentifier extends string string string { readonly __object?: TObjectUniversalIdentifier };这是一个 branded string运行时它就是一个普通字符串记录 id类型层面则通过可选的__object品牌字段携带了对象标识供推断阶段静态读取。构建期推断产出的InputJsonSchema类型定义在 input-json-schema.type.ts其中type字段支持record与records数组形式并带有objectUniversalIdentifier字段承载目标对象标识——这正是渲染记录选择器所需的信息。测试用例如何验证推断结果SDK 中有一个针对性的集成测试 manifest-build-logic-function-input-schema.spec.ts它对rich-appfixture 执行buildManifest并断言记录型输入被正确解析为标准对象与 App 对象的 universal identifierexpect(logicFunction?.workflowActionTriggerSettings?.inputSchema).toEqual([ { type: object, properties: { companyId: { type: record, objectUniversalIdentifier: STANDARD_OBJECTS.company.universalIdentifier, }, postCardIds: { type: records, objectUniversalIdentifier: POST_CARD_OBJECT_UNIVERSAL_IDENTIFIER, }, }, }, ]);这印证了映射规则单值TwentyRecord...→{ type: record, objectUniversalIdentifier }数组TwentyRecord...[]→{ type: records, objectUniversalIdentifier }。handler 在运行时实际收到什么理解TwentyRecordTUid的运行时形态对正确编写 handler 至关重要它是 brandedstring因此params.companyId是一个记录 id字符串params.postCardIds是一个记录 id 数组。这与运行时实际投递的数据一致——工作流动作会把所选记录的 id 原样传给 handler或者把所绑定的{{variable}}变量解析后的值直接传入。因此handler 必须接受 id而不是完整记录对象。仓库中 People Data Labs 应用people-data-labs的逻辑函数正是这一模式的范例。它定义了如下输入类型export type RecordInput string | { id?: string | null };并在实际使用前通过extractRecordIds辅助函数归一化输入。从该应用的结构和测试看extract-record-ids.ts 及其配套测试extract-record-ids.test.ts覆盖了多种输入形态纯 id 数组、带id字段的对象数组、混合脏数据{ id: null }、{}、空字符串会被过滤以及单个对象/字符串和null/undefined。这说明即使类型系统声明了 branded string防御性地归一化输入仍是实际工程中的标准做法。如果 handler 需要完整记录而非 id正确姿势是通过 Core API client 按 id 自行拉取而不是期望运行时把完整记录递进 params。小结与适用前提推断是 manifest build 期的静态行为依赖 handler 参数类型的字面量信息显式inputSchema永远优先并整体接管该 surface。TwentyRecorduuid 字面量是绑定记录型输入的唯一可靠方式universal identifier 直接取自STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS标准对象或defineObject(...)的配置App 对象。handler 收到的是记录 id或 id 数组需要完整记录时应经 Core API 按 id 查询。本文所述机制以当前仓库packages/twenty-sdk与packages/twenty-shared的实际实现为准TwentyRecord推断依赖字面量类型保留若项目编译配置或工具链擦除了内联字面量类型推断将退化。【免费下载链接】twentyThe open alternative to Salesforce, designed for AI.项目地址: https://gitcode.com/GitHub_Trending/tw/twenty创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考