npm package: @lark-apaas/action-plugin-core
Description: Core library for platform action execution system
Latest version: 0.1.0

# @lark-apaas/action-plugin-core

aPaaS 平台 Action 插件核心开发包。

## 安装

```bash
pnpm add @lark-apaas/action-plugin-core zod@^3.25.76
```

> **重要**: 请使用 zod v3.25.76 或更高版本。项目统一使用 zod v3，以确保 Schema 定义和类型推导的兼容性。

## 快速开始

### 基础插件

```typescript
import { definePlugin } from '@lark-apaas/action-plugin-core';
import { z } from 'zod';

export default definePlugin([
  {
    name: 'sayHello',
    input: z.object({ name: z.string() }),
    output: z.object({ greeting: z.string() }),
    handler: async (context, input) => {
      return { greeting: `Hello, ${input.name}!` };
    },
  },
]);
```

### 流式插件

```typescript
import { definePlugin, StreamTextOutput, Aggregators } from '@lark-apaas/action-plugin-core';
import { z } from 'zod';

export default definePlugin([
  {
    name: 'chat',
    outputMode: 'stream',
    input: z.object({ message: z.string() }),
    output: StreamTextOutput,
    aggregate: Aggregators.text,
    async *handler(context, input) {
      yield { data: { content: 'Hello, ' } };
      yield { data: { content: input.message } };
      yield { data: { content: '!' } };
    },
  },
]);
```

## 核心概念

### 输出模式

| 模式     | 说明             | handler 返回       | 执行方法      |
| -------- | ---------------- | ------------------ | ------------- |
| `unary`  | 单次响应（默认） | `Promise<T>`       | `run()`       |
| `stream` | 流式响应         | `AsyncIterable<T>` | `runStream()` |

### 流式聚合

流式 action 可以定义 `aggregate` 聚合器，用于将多个 chunk 聚合为单个结果：

```typescript
// 预定义聚合器
aggregate: Aggregators.text; // 文本拼接
aggregate: Aggregators.collect; // 数组收集
aggregate: Aggregators.last; // 取最后一个
aggregate: Aggregators.first; // 取第一个
aggregate: Aggregators.mergeRecords; // 合并记录

// 自定义聚合器
aggregate: (chunks) => ({
  total: chunks.reduce((sum, c) => sum + c.value, 0),
});
```

使用聚合：

```typescript
const chunks = [];
for await (const chunk of instance.runStream('chat', context, input)) {
  chunks.push(chunk);
}
const result = instance.aggregate('chat', chunks);
```

## API

### definePlugin

```typescript
function definePlugin<TConfig>(
  actions: ActionDefinition[],
  options?: { config?: ZodSchema<TConfig> },
): Plugin<TConfig>;
```

### ActionDefinition

| 字段         | 类型                  | 必填 | 说明        |
| ------------ | --------------------- | ---- | ----------- |
| `name`       | `string`              | 是   | Action 名称 |
| `input`      | `ZodSchema`           | 是   | 输入 Schema |
| `output`     | `ZodSchema`           | 否   | 输出 Schema |
| `outputMode` | `'unary' \| 'stream'` | 否   | 输出模式    |
| `aggregate`  | `StreamAggregator`    | 否   | 流式聚合器  |
| `handler`    | `Function`            | 是   | 处理函数    |

### PluginInstance

```typescript
interface PluginInstance {
  // Unary
  run(actionName, context, input): Promise<unknown>;

  // Stream
  runStream(actionName, context, input): AsyncIterable<unknown>;
  isStreamAction(actionName): boolean;
  getOutputMode(actionName): 'unary' | 'stream' | undefined;
  aggregate<T>(actionName, chunks): T;

  // 通用
  hasAction(actionName): boolean;
  listActions(): string[];
  getInputSchema(actionName): ZodSchema | undefined;
  getOutputSchema(actionName, input): ZodSchema | undefined;
}
```

## 流式工具

### Stream Helper

```typescript
import { Stream } from '@lark-apaas/action-plugin-core';

// 创建流
Stream.of(item1, item2, item3);
Stream.from(asyncIterable);
Stream.once(singleItem);
Stream.empty();

// 转换
stream.map(fn);
stream.filter(fn);
stream.take(n);
stream.concat(otherStream);
```

### 标准 Schema

```typescript
import { streamOutput, StreamTextOutput } from '@lark-apaas/action-plugin-core';

// 自定义流式输出 schema
const MyChunkSchema = streamOutput(z.object({ value: z.number() }));
// 等价于: z.object({ data: z.object({ value: z.number() }) })

// 标准文本流 schema
StreamTextOutput; // { data: { content: string } }
```

## Zod 扩展

本库扩展了 zod，提供 `.format()` 和 `.defaultValue()` 方法，用于在 JSON Schema 中添加元数据。

### .format()

设置 JSON Schema 的 `format` 字段，用于标注字符串格式：

```typescript
import { z } from 'zod';
import '@lark-apaas/action-plugin-core'; // 导入即启用扩展

const schema = z.object({
  email: z.string().format('email'),
  website: z.string().format('uri'),
  createdAt: z.string().format('date-time'),
});
```

支持的 format 类型：`date-time`、`date`、`time`、`duration`、`email`、`uri`、`uri-reference`、`uuid`、`hostname`、`ipv4`、`ipv6`、`regex` 及自定义字符串。

### .defaultValue()

设置 JSON Schema 的 `default` 字段，**仅作为元数据标注**，不影响字段的必填状态：

```typescript
const schema = z.object({
  name: z.string().defaultValue('张三'), // required，JSON Schema 中有 default
  age: z.number().defaultValue(18), // required，JSON Schema 中有 default
  status: z.string().default('active'), // optional，zod 原生 default
});
```

**与 zod 原生 `.default()` 的区别：**

| 方法                   | 字段状态 | 解析行为         | JSON Schema      |
| ---------------------- | -------- | ---------------- | ---------------- |
| `.default(value)`      | 可选     | 缺失时使用默认值 | `default: value` |
| `.defaultValue(value)` | 必填     | 无特殊处理       | `default: value` |

## 错误处理

```typescript
import { PluginError, PluginErrorCode } from '@lark-apaas/action-plugin-core';

try {
  await instance.run('action', context, input);
} catch (error) {
  if (error instanceof PluginError) {
    switch (error.code) {
      case PluginErrorCode.ACTION_NOT_FOUND:
      case PluginErrorCode.INVALID_INPUT:
      case PluginErrorCode.INVALID_OUTPUT:
      case PluginErrorCode.EXECUTION_ERROR:
    }
  }
}
```

## 文档

- [definePlugin API 文档](./docs/definePlugin.md)
- [设计文档](./docs/DESIGN.md)

## License

MIT