跳转到内容

Script

本文档规定了脚本扩展,这是一个灵活的数据层解决方案,通过多个执行上下文实现可扩展功能。脚本扩展为数据处理工作流程中的自定义逻辑执行提供了统一的接口。

支持的脚本类型包括:

  • LLM 工具:作为 AI 代理的可调用工具
  • 表格动作:在表格记录上触发的自定义动作
  • 文档动作:在文档上触发的智能处理
  • 文件动作:后台处理文件的一键操作
  • 用户自定义函数 (UDF):可在 SQL 查询中调用的数据库函数

脚本扩展通过提供一个标准化框架来在多个上下文中执行自定义逻辑,满足了可扩展数据处理功能的需求。本规范定义了每种支持的脚本类型的元配置结构和执行模式。

type 属性设置为 "tool" 时,脚本作为大型语言模型 (LLM) 工作流程中的可调用工具,使 AI 代理能够执行具有结构化输入/输出模式的自定义函数。

interface ToolMeta {
type: "tool"
funcName: string
tool: {
name: string
description: string
inputJSONSchema: JSONSchema
outputJSONSchema: JSONSchema
}
}
export const meta = {
type: "tool",
funcName: "hello",
tool: {
name: "hello",
description: "这是一个 hello world 块",
inputJSONSchema: {
type: "object",
properties: {
name: {
type: "string",
},
},
},
outputJSONSchema: {
type: "string",
},
},
}
export function hello({ name }: { name: string }) {
return `Hello, ${name}!`
}

type 属性设置为 "tableAction" 时,脚本作为表格级动作,可以在选定记录上触发。这些动作通过上下文菜单访问,使用自定义功能扩展表格界面。

interface TableActionMeta {
type: "tableAction"
funcName: string
tableAction: {
name: string
description: string
}
}

表格动作函数接收两个参数:

  • input: 作为 Record<string, any> 的选定记录数据
  • ctx: 包含 tableIdviewIdrowIdenv 的上下文对象
export const meta = {
type: "tableAction",
funcName: "toggleChecked",
tableAction: {
name: "切换选中状态",
description: "切换选定记录的选中状态",
},
}
export async function toggleChecked(
input: Record<string, any>,
ctx: {
tableId: string
viewId: string
rowId: string
}
) {
const { tableId, viewId, rowId, env } = ctx
console.log(env.MY_SECRET) // 获取环境变量
await eidos.currentSpace.table(tableId).rows.update(rowId, {
checked: !input.checked,
})
return {
success: true,
}
}

type 属性设置为 "docAction" 时,脚本作为文档级动作,可以在特定文档上触发。这些动作通过文档动作菜单访问,让您的文档变得更加智能和自动化。

interface DocActionMeta {
type: "docAction"
funcName: string
docAction: {
name: string
description: string
}
}

文档动作函数接收两个参数:

  • input: 作为 Record<string, any> 的输入参数
  • ctx: 包含 docIdenv 的上下文对象
export const meta = {
type: "docAction",
funcName: "calculateCompletion",
docAction: {
name: "计算完成度",
description: "计算文档中待办事项的完成百分比",
},
}
export async function calculateCompletion(
input: Record<string, any>,
ctx: {
docId: string
}
) {
const { docId, env } = ctx
const doc = await eidos.currentSpace.doc.getMarkdown(docId)
// 从 markdown 中提取 checkbox 的完成占比
const uncheckedCount = doc
.split("\n")
.filter((line) => line.startsWith("- [ ]")).length
const checkedCount = doc
.split("\n")
.filter((line) => line.startsWith("- [x]")).length
const totalCount = uncheckedCount + checkedCount
const completion = totalCount > 0 ? (checkedCount / totalCount) * 100 : 0
await eidos.currentSpace.doc.setProperties(docId, {
completion,
})
return {
completion,
}
}

type 属性设置为 "fileAction" 时,脚本作为文件级动作,可以在特定文件上触发。这些动作通过文件右键菜单访问,实现后台文件处理功能,无需打开 UI 界面。

interface FileActionMeta {
type: "fileAction"
funcName: string
fileAction: {
name: string
description: string
extensions: string[] // 支持的文件扩展名,如 [".jpg", ".png"]
icon?: string // 可选图标
}
}

文件动作函数接收两个参数:

  • filePath: 文件路径字符串(格式同 File Handler,支持 ~/@/ 前缀)
  • ctx: 上下文对象,包含 env 环境变量
export const meta = {
type: "fileAction",
funcName: "compressImage",
fileAction: {
name: "压缩图片",
description: "将图片压缩到原大小的 50%",
extensions: [".jpg", ".jpeg", ".png"],
icon: "🗜️"
}
}
export async function compressImage(
filePath: string,
ctx: {
env: Record<string, string>
}
) {
const { env } = ctx
try {
// 读取原始文件
const data = await eidos.currentSpace.fs.readFile(filePath)
// 压缩图片(使用第三方库,如 browser-image-compression)
const compressed = await compressImageData(data, {
maxSizeMB: 1,
maxWidthOrHeight: 1920
})
// 生成新文件路径
const newPath = filePath.replace(/(\.\w+)$/, '_compressed$1')
await eidos.currentSpace.fs.writeFile(newPath, compressed)
// 显示成功通知
eidos.currentSpace.notify({ title: "成功", description: `已压缩并保存到 ${newPath}` })
return {
success: true,
outputPath: newPath,
originalSize: data.byteLength,
compressedSize: compressed.byteLength
}
} catch (error) {
eidos.currentSpace.notify({ title: "错误", description: `压缩失败: ${error.message}` })
return {
success: false,
error: error.message
}
}
}
  1. 用户在文件树中右键点击文件
  2. 看到”文件动作”子菜单,列出所有支持该扩展名的 fileAction
  3. 点击某个动作(如”压缩图片”)
  4. 脚本在后台执行
  5. 完成后显示通知,告知结果

与 File Handler 相同,使用 eidos.currentSpace.fs API 访问文件:

// 读取文本文件
const text = await eidos.currentSpace.fs.readFile(filePath, "utf8")
// 读取二进制文件
const data = await eidos.currentSpace.fs.readFile(filePath)
// 写入文件
await eidos.currentSpace.fs.writeFile(filePath, content, "utf8")
// 获取文件信息
const stats = await eidos.currentSpace.fs.stat(filePath)

更多文件系统 API 详情,请参阅 Space API 参考 - 文件系统 API

type 属性设置为 "udf" 时,脚本创建可以在 SQL 查询中调用的数据库函数,扩展数据库的计算能力。

interface UDFMeta {
type: "udf"
funcName: string
udf: {
name: string
deterministic?: boolean
}
}

标量 UDF 对单个值进行操作,每次调用返回单个结果。

export const meta = {
type: "udf",
funcName: "add",
udf: {
// add 是 SQL 中的保留字,所以我们使用不同的名称
name: "myAdd",
deterministic: true,
},
}
function add(a: number, b: number) {
return a + b
}

脚本执行应该被适当沙箱化,以防止未经授权的系统访问。实现必须验证输入参数,并根据执行上下文强制执行适当的访问控制。

  • 所有脚本必须导出符合指定接口的 meta 对象
  • meta.funcName 属性中的函数名必须与实际导出的函数匹配
  • 应该为所有脚本类型实现输入验证
  • 错误处理在所有执行上下文中必须保持一致

本规范可能会扩展以支持其他脚本类型,例如:

  • 事件处理器
  • 数据验证器
  • 自定义字段类型
  • 工作流触发器