npm package: @plolink/sdk
Description: Plolink 开放平台官方 SDK
Author: Plolink Team
Latest version: 2.0.5

# @plolink/sdk

Plolink 开放平台官方 SDK，提供完整的 API 调用能力。

## 特性

- 🔐 **统一认证**：使用 Bearer Token 认证，支持 ApiKey 和 SessionId
- 🔄 **智能轮询**：内置指数退避轮询机制，自动处理异步任务
- 📦 **分包导入**：支持按需导入，减少打包体积
- 🌍 **跨环境**：同时支持 Node.js 和浏览器环境
- 📝 **类型安全**：完整的 TypeScript 类型定义
- 🔌 **可扩展**：支持自定义日志钩子，轻松集成 Sentry 等监控系统
- 📚 **文档齐全**：代码即文档，完整的 TSDoc 注释

## 安装

```bash
npm install @plolink/sdk
# 或
pnpm add @plolink/sdk
# 或
yarn add @plolink/sdk
```

## 快速开始

### 使用 ApiKey

```typescript
import { PlolinkClient } from '@plolink/sdk';

const client = new PlolinkClient({
  token: 'pl_your-api-key',
  logger: (level, message, data) => {
    console.log(`[${level}] ${message}`, data);
  }
});

// 检查健康状态
const health = client.healthCheck();
console.log(health);
```

### 使用 SessionId（登录后获取）

```typescript
import { PlolinkClient } from '@plolink/sdk';

// 先登录获取 sessionId
const loginResponse = await fetch('https://api.plolink.com/api/v1/auth/login/password', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: 'user@example.com', password: 'password' })
});
const { sessionId } = await loginResponse.json();

// 使用 sessionId 创建客户端
const client = new PlolinkClient({
  token: sessionId,
  baseUrl: 'https://api.plolink.com'
});
```

## 业务模块

SDK 提供多个业务模块，支持按需导入。

### LLM 通用接口模块 (LLM)

LLM 模块提供通用的大语言模型调用能力，兼容 OpenAI API 格式：

- **聊天完成** (`chat`): 调用 LLM 模型进行对话，支持多轮对话
- **模型列表** (`getModels`): 获取所有可用模型及价格信息

```typescript
import { PlolinkClient } from '@plolink/sdk';
import { LLM } from '@plolink/sdk/llm';

const client = new PlolinkClient({ token: 'sk-your-api-key' });
const llm = new LLM(client);

// 获取可用模型
const models = await llm.getModels();
console.log('可用模型：', models.map(m => m.name));

// 调用聊天完成
const response = await llm.chat({
  model: 'deepseek-v3-1-terminus',
  messages: [
    { role: 'system', content: '你是一个专业的编程助手' },
    { role: 'user', content: '如何用 TypeScript 实现单例模式？' }
  ],
  temperature: 0.7
});

console.log('回复：', response.choices[0].message.content);
console.log('消耗 tokens：', response.usage.total_tokens);
```

详细文档请参考 [docs/modules/llm.md](./docs/modules/llm.md)

### 心理评测模块 (PsychologyTest)

心理评测模块提供完整的心理评测能力，包括：

- **发起评测** (`initiate`): 根据题组代码创建评测会话并生成题目
- **提交答题** (`submit`): 提交用户答题记录并自动计算结果
- **获取详情** (`getDetail`): 获取评测会话详情和AI分析结果
- **获取答题记录** (`getAnswers`): 获取完整的答题记录列表
- **列表查询** (`listTestSessions`): 查询评测会话列表，支持分页和筛选 ✨
- **删除会话** (`deleteTestSession`): 软删除评测会话记录 ✨

```typescript
import { PlolinkClient } from '@plolink/sdk';
import { PsychologyTest } from '@plolink/sdk/psychology-test';

const client = new PlolinkClient({ token: 'your-token' });
const psychologyTest = new PsychologyTest(client);

// 发起心理评测
const initResult = await psychologyTest.initiate({
  groupCodes: ['family_parenting', 'disc'],
  businessModule: 'talent_assessment',
  businessCode: 'job_match',
  businessId: 'candidate_123',
  needAnalysis: true,
  analysisPrompt: '请分析候选人的性格特点',
  teamId: 'team_123'
});

// 提交答题
const submitResult = await psychologyTest.submit({
  sessionId: initResult.sessionId,
  answers: [...],
  duration: 480000
});

// 列表查询评测会话 ✨ 新增
const sessions = await psychologyTest.listTestSessions({
  page: 1,
  size: 20,
  status: 'COMPLETED',
  analysisStatus: 'COMPLETED'
});

// 删除评测会话 ✨ 新增
await psychologyTest.deleteTestSession(sessionId);
```

详细文档请参考 [docs/modules/psychology-test.md](./docs/modules/psychology-test.md)

### AI 报告写作模块 (ReportWriter)

AI 报告写作模块提供自动生成结构化文章的能力，支持：

- **创建报告** (`create`): 根据指令和材料生成报告任务
- **查询列表** (`list`): 分页查询报告列表，支持多维度筛选
- **获取详情** (`getDetail`): 获取报告详情和生成进度
- **删除报告** (`delete`): 软删除报告记录
- **导出 Markdown** (`getMarkdown`): 获取 Markdown 格式的报告内容

```typescript
import { PlolinkClient } from '@plolink/sdk';
import { ReportWriter } from '@plolink/sdk/report-writer';

const client = new PlolinkClient({ token: 'your-token' });
const reportWriter = new ReportWriter(client);

// 创建报告
const createResult = await reportWriter.create({
  name: '2024年度总结报告',
  instruction: '请根据提供的材料，撰写一份年度工作总结报告',
  businessCode: 'annual-report',
  externalId: '2024-001',
  articleLevel: 3,
  materials: [
    {
      type: 'text',
      content: '2024年完成了10个项目，总营收增长30%...'
    }
  ]
});

// 轮询检查状态
let detail = await reportWriter.getDetail(createResult.id);
while (detail.status !== 'COMPLETED' && detail.status !== 'FAILED') {
  await new Promise(resolve => setTimeout(resolve, 5000));
  detail = await reportWriter.getDetail(createResult.id);
}

// 获取 Markdown 格式
if (detail.status === 'COMPLETED') {
  const markdown = await reportWriter.getMarkdown(createResult.id);
  console.log(markdown.markdown);
}
```

详细文档请参考 [docs/modules/report-writer.md](./docs/modules/report-writer.md)

### 预设Agent任务模块 (PresetAgentTask)

预设Agent任务模块提供开箱即用的业务能力，完全隐藏底层Agent Task实现细节：

- **预设管理** (`create`, `list`, `getById`, `update`, `delete`): 创建和管理预设配置
- **预设执行** (`execute`): 通过code快速执行预设任务
- **执行管理** (`listExecutions`, `getExecutionById`, `cancelExecution`, `retryExecution`): 查询和管理执行记录
- **配置迁移** (`export`, `import`): 导出/导入预设配置，支持跨团队迁移

```typescript
import { PlolinkClient } from '@plolink/sdk';
import { PresetAgentTask } from '@plolink/sdk/preset-agent-task';

const client = new PlolinkClient({ token: 'your-token' });
const presetAgentTask = new PresetAgentTask(client);

// 执行预设任务
const result = await presetAgentTask.execute({
  code: 'talent-resume-parse',
  additionalPrompt: '请特别关注技能匹配度',
  inputFileId: 'file-resume-123'
});

console.log('执行ID:', result.executionId);

// 轮询查询结果
let execution;
do {
  await new Promise(resolve => setTimeout(resolve, 5000));
  execution = await presetAgentTask.getExecutionById(result.executionId);
  console.log('状态:', execution.status);
} while (execution.status === 'INITIALIZING' || execution.status === 'RUNNING');

// 获取结果
if (execution.status === 'COMPLETED') {
  console.log('输出文件:', execution.outputFileId);
  console.log('费用:', execution.metrics.totalCost, 'USD');
}

// 或者通过Webhook接收结果通知
// 在系统中配置Webhook订阅 "preset-agent-task" 模块
```

**注意事项：**
- ✅ 完全隐藏Agent Task细节，不暴露 `agentTaskId`、`runId`
- ✅ 支持轮询和Webhook两种方式获取执行结果
- ✅ 支持配置导出/导入，方便跨团队迁移

### 其他模块

其他业务模块的详细文档请参考 docs/modules/ 目录

## 高级功能

### 自定义日志

```typescript
import { PlolinkClient } from '@plolink/sdk';
import * as Sentry from '@sentry/node';

const client = new PlolinkClient({
  token: 'pl_your-api-key',
  logger: (level, message, data) => {
    if (level === 'error') {
      Sentry.captureMessage(message, {
        level: 'error',
        extra: data
      });
    }
  }
});
```

### 使用轮询器

```typescript
import { Poller } from '@plolink/sdk';

const poller = new Poller({
  task: () => fetch('/api/order/123').then(r => r.json()),
  onResult: (data) => {
    console.log('Order status:', data.status);
  },
  shouldStop: (data) => data.status === 'success',
  initialInterval: 1000,
  maxInterval: 30000,
  backoffFactor: 1.5
});

// 启动轮询
poller.start();

// 停止轮询
poller.stop();
```

### 使用事件发射器

```typescript
import { EventEmitter } from '@plolink/sdk';

const emitter = new EventEmitter();

// 订阅事件
const unsubscribe = emitter.on('status-change', (data) => {
  console.log('Status changed:', data);
});

// 触发事件
emitter.emit('status-change', { status: 'completed' });

// 取消订阅
unsubscribe();
```

## 配置选项

```typescript
interface SDKConfig {
  /**
   * API 基础 URL
   * @default 'https://hiring.djangotech.com/'
   */
  baseUrl?: string;

  /**
   * 认证 Token (ApiKey 或 SessionId)
   * - ApiKey: pl_ 开头的字符串
   * - SessionId: 登录后返回的 UUID 格式字符串
   */
  token: string;

  /**
   * 自定义日志钩子函数
   */
  logger?: (level: string, message: string, data?: any) => void;

  /**
   * 请求超时时间（毫秒）
   * @default 10000
   */
  timeout?: number;
}
```

## 错误处理

所有错误都会被转换为 `PlolinkError`：

```typescript
import { PlolinkClient, PlolinkError } from '@plolink/sdk';

try {
  const result = await client.someMethod();
} catch (error) {
  if (error instanceof PlolinkError) {
    console.error(`Error ${error.code}: ${error.message}`);
    console.error('Additional data:', error.data);
  }
}
```

## 环境检测

```typescript
import { isNode, isBrowser, getEnvironment } from '@plolink/sdk';

if (isNode) {
  console.log('Running in Node.js');
}

if (isBrowser) {
  console.log('Running in browser');
}

console.log('Environment:', getEnvironment());
```

## 开发

### 构建

```bash
pnpm install
pnpm build
```

### 测试

```bash
pnpm test
pnpm test:watch
```

### 生成文档

```bash
pnpm docs
```

### 类型检查

```bash
pnpm typecheck
```

## 技术支持

- 📧 Email: admin@wj2015.com