# 候选人库

Version: a2bc6a0f021ec643

模块地址：https://sandbox.maimai.dev.planahr.top/api/v1/candidate-library/tools；权限 candidates:read / candidates:write。写权限不包含读权限，均不扩大用户自身权限。

操作名：search、detail、contacts、notes、documentInfo、documents、resumeContent、duplicates、create、update、note。工具名称前缀 candidate_library_ 不用于 POST 的 operation。

GET 加 ?operation=操作名 只取单项 schema；?view=summary 只取目录。POST 不带查询参数，使用 {operation,input} 和 Content-Type: application/json。

```bash
curl 'https://sandbox.maimai.dev.planahr.top/api/v1/candidate-library/tools?operation=search' \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

- 所有 ID 都从实际接口结果取得。候选人 ID 是字符串，岗位/客户 ID 是整数；成员使用 context 返回的 membership ID，不用姓名猜身份。
- 新建前 duplicates，疑似重复交用户判断，不自动合并。候选人库与脉脉筛选数据库独立。
- 同组织普通同事可读取所有候选人资料，不要求负责人/协作者关系，网页与 Agent 一致；写入仍校验原编辑权限，不开放跨组织或作者私密流程笔记。detail 只给摘要；contacts 需 candidates:read + sensitive:contacts，返回库内电话/邮箱（本库不存微信）；notes 需 sensitive:notes。documentInfo 与 GET /api/v1/candidate-library/{id}/document?download=0 或 1 需 candidates:read + sensitive:documents，仍用相同 Bearer。不要猜附件路径。
- 流程详情中的历史/备注同样需 sensitive:notes；旧连接不会自动获得新权限，确有业务需要才重新登录申请。电话/邮箱查重参数也需 sensitive:contacts。所有读取均留痕，敏感读取可能返回 429 / SENSITIVE_ACCESS_LIMIT；不要换会话或 Agent 绕过用户级限制。
- 完整履历：create/update 的 data 可选 rawResumeText（原样保留换行）、workExperiences、educationExperiences。工作段字段 company/title/startDate/endDate/current/description；教育段 school/degree/major/startDate/endDate/description。未知日期用 null 或省略，日期为 YYYY、YYYY-MM 或 YYYY-MM-DD。update 省略字段不变，显式 [] 清空对应经历数组；提交数组整体替换。detail 的 workExperienceSummary / educationExperienceSummary 只给基本字段，不给描述；resumeContent 读取同组织全文和完整经历，需 candidates:read + sensitive:documents。列表和写入回执不返回原文。历史字段不重解析、不改写；无法规范化的旧 experience/data 在敏感结果的 legacyContent 中保留。
- 附件上传不是 JSON 工具调用：POST /api/v1/candidate-library/{id}/documents，Authorization 仍为 Bearer，使用 multipart/form-data，唯一文件字段 file，其他字段 version（当前候选人版本）、kind（resume/screenshot/other，默认 resume）、requestId。需要 candidates:write + 对象编辑权限；上传人由登录身份确定，不能指定。不要把文件转成 Base64。GET tools?operation=documents 的 binaryUpload 给出元数据 inputSchema 与实际限制。默认每件 20 MiB，履历正文+经历合计 200000 字符（经历按 JSON 长度），配置可调整。支持 PDF/DOC/DOCX/PNG/JPG/JPEG，扩展名与文件签名须匹配。
- documents 分页列出同组织附件 documentId/name/type/bytes/sha256/kind/uploadedAt/uploadedBy，需 candidates:read + sensitive:documents。使用 GET /api/v1/candidate-library/{id}/documents/{documentId}?download=1 下载原件，download=0 预览 PDF/图片；DOC/DOCX 原样下载。历史主附件 ID 为 legacy，旧 /{id}/document 仍可用，没历史主附件时返回最新上传原件。一个候选人可加多份；同一截图可对多个候选人分别上传，产生各自独立关联与权限。写入返回更新后的 version；重试保留原 version、requestId、文件名、kind 和原文件。409 VERSION_CONFLICT 先读最新版本后用新 requestId，IDEMPOTENCY_CONFLICT 不可盲重试；413 缩小内容，415 检查类型，503 使用原请求有限重试。

以下仅为虚构模板；ID、version 必须从真实读取结果取得，写入 requestId 为每个逻辑动作生成且重试保持不变。

### 分页搜索候选人（只读）

POST /api/v1/candidate-library/tools

```json
{
  "operation": "search",
  "input": {
    "query": "芯片",
    "page": 1,
    "pageSize": 20
  }
}
```

### 读取候选人详情和版本（只读）

POST /api/v1/candidate-library/tools

```json
{
  "operation": "detail",
  "input": {
    "id": "1"
  }
}
```

### 检查可能重复的候选人（只读）

POST /api/v1/candidate-library/tools

```json
{
  "operation": "duplicates",
  "input": {
    "name": "示例候选人"
  }
}
```

### 追加跟进备注（写入示例）

POST /api/v1/candidate-library/tools

```json
{
  "operation": "note",
  "input": {
    "id": "1",
    "content": "示例：候选人希望先了解岗位职责。",
    "requestId": "example-note-001"
  }
}
```

### 按版本修改候选人（写入示例）

POST /api/v1/candidate-library/tools

```json
{
  "operation": "update",
  "input": {
    "id": "1",
    "version": 0,
    "data": {
      "city": "上海"
    },
    "requestId": "example-update-001"
  }
}
```
