确认当前身份和成员 ID 只读
POST /api/v1/hiring/tools
{
"operation": "read",
"input": {
"resource": "context",
"input": {}
}
}这是完整参考手册,不是默认上下文。Agent 先 GET /api/v1/agent/guide,直接返回精简文本;/agent/SKILL.md 和 guide.md 保持兼容。仅在需要时读 references 下的相关文档,不必再读整个 manifest 或本手册。阅读不需要登录,也不会触发任何业务操作。
本服务是 HTTP JSON 工具适配器,不是标准 MCP transport。不要尝试 /mcp、直接读数据库、调用旧平台端口或自动点击管理页面。若宿主支持 function calling,可按实时 schema 注册本地函数,函数内部转发到这里。
这是隔离测试沙箱,全部为虚构数据。下方飞书协议流程使用模拟身份提供者,不会访问真实飞书:让用户在模拟授权页面输入专用沙箱口令并选择测试身份;不要输入真实凭证或扫码。本环境签发 sandbox- 测试凭证,仅用于本沙箱;真实招聘、发送、通知和模型调用已禁用。
Agent 不需要应用密钥或平台自建授权码。用户在飞书页面登录/扫码并确认后即完成鉴权,不存在第二次平台批准。用户必须是本平台所属飞书租户中已启用的成员。
第一步:发起连接。以下默认只请求四类读取权限;任务确需写入时再增加对应的 :write scope。写权限不会自动包含读取权限,需要两者时要一并申请。agent_name 填可识别的名称,不代表可信身份。
curl 'https://sandbox.maimai.dev.planahr.top/api/v1/agent-auth/device' \
-H 'Content-Type: application/json' \
--data '{
"agent_name": "我的招聘助手",
"scope": "candidates:read jobs:read clients:read hiring:read"
}'| 返回字段 | 用法 |
|---|---|
| verification_uri_complete | 把此飞书完整验证链接展示给用户,由用户打开登录/扫码。 |
| verification_uri / user_code | 备用飞书验证地址和飞书验证码;不是平台生成的授权码。 |
| device_code | 保存在 Agent 端,仅用于 token 轮询;不得展示或泄露。 |
| interval / expires_in | 轮询间隔(秒)和此次连接的有效期(秒);以实际返回值为准。 |
| business_scope | 本次申请的平台业务权限上限,不会扩大用户本身权限。 |
第二步:让用户完成飞书验证,然后按返回 interval 轮询。把下例 <DEVICE_CODE> 替换为上一步保存的值,不要拼到 URL 中。
curl 'https://sandbox.maimai.dev.planahr.top/api/v1/agent-auth/token' \
-H 'Content-Type: application/json' \
--data '{
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
"device_code": "<DEVICE_CODE>"
}'| OAuth error | 处理 |
|---|---|
| authorization_pending | 等待至少 interval 秒继续,不是登录失败。 |
| slow_down | 在当前轮询间隔上增加至少 5 秒。 |
| access_denied / expired_token / invalid_grant | 停止本次流程,告知用户;如仍需要连接,重新发起登录。 |
| temporarily_unavailable / 429 | 有限退避,并遵守 Retry-After;不要高频轮询。 |
成功后保存 access_token、可选的 refresh_token 及它们的有效期。token_type 为 Bearer;scope 是飞书返回的 scope,business_scope 才是平台业务权限上限。可选 client_id=planahr-agent 只是本服务的公开客户端配置名,不是飞书 app_id,也不是密钥。
续期同样由飞书签发凭证。使用最近一次返回的 refresh_token;刷新需要串行,保存返回的最新 token/有效期(飞书可能轮换,也可能保留 refresh_token)。没有可用续期凭证时重新登录。
把下例 <REFRESH_TOKEN> 替换为最近保存的续期凭证。调用业务接口时,下例环境变量 ACCESS_TOKEN 则替换为当前 access_token。
curl 'https://sandbox.maimai.dev.planahr.top/api/v1/agent-auth/token' \
-H 'Content-Type: application/json' \
--data '{
"grant_type": "refresh_token",
"refresh_token": "<REFRESH_TOKEN>"
}'用户可在平台的“Agent 授权”页面查看和撤销自己的连接。平台撤销不等于撤销整个飞书应用授权,也不会让网页登录退出。
| 业务模块 | GET / POST 地址 | 能力 |
|---|---|---|
| 候选人库 | /api/v1/candidate-library/tools | 支持完整履历和多附件上传。普通详情不含联系方式、备注或简历原文;敏感信息需单独 scope。与招聘筛选数据库独立。 |
| 岗位 | /api/v1/job-library/tools | 查询公司下的岗位,维护岗位基本信息。暂停/关闭岗位请走招聘流程的 jobState,不存在对外的 close 工具。 |
| 客户公司 | /api/v1/client-library/tools | 查询和维护客户公司。新公司的岗位应先关联真实的客户公司。 |
| 招聘流程 | /api/v1/hiring/tools | 管理候选人与岗位之间的流程、阶段、负责人、协作、安排及备注。读取资源包括 context、flows、detail、dashboard、jobImpact、personalNote。 |
同一地址:GET ?operation=search 只返回该操作的 {tools:[{name,inputSchema,description?,annotations?}]};未知操作返回 404。GET ?view=summary 仅返回工具名称和描述,不含 schema,用于不知道操作名时发现能力。裸 GET 仍兼容返回整个模块,不建议默认使用。POST 执行 {operation,input}。同一会话复用已读 schema,验证错误或接口变化时按需刷新。未知字段会被拒绝;结果直接为 JSON,没有 JSON-RPC 包装。
curl 'https://sandbox.maimai.dev.planahr.top/api/v1/candidate-library/tools?operation=search' \
-H "Authorization: Bearer $ACCESS_TOKEN"例如工具名 candidate_library_search 对应 POST operation="search",不是完整工具名。input 必须符合该工具的 inputSchema。下面是可以直接改造的只读调用:
curl 'https://sandbox.maimai.dev.planahr.top/api/v1/candidate-library/tools' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
--data '{
"operation": "search",
"input": {
"query": "芯片",
"page": 1,
"pageSize": 20
}
}'读取自己的身份/组织和有效成员 ID:调用 hiring 的 read,resource="context"。返回 members、membershipId、displayName、organizationId、角色及 visibleMemberIds;成员目录不代表这些成员的业务数据全部可读或可写。
{
"operation": "read",
"input": {
"resource": "context",
"input": {}
}
}| Scope | 含义 |
|---|---|
| candidates:read / candidates:write | 候选人库读取 / 写入(仍受用户实时权限约束) |
| jobs:read / jobs:write | 岗位读取 / 写入(仍受用户实时权限约束) |
| clients:read / clients:write | 客户公司读取 / 写入(仍受用户实时权限约束) |
| hiring:read / hiring:write | 招聘流程读取 / 写入(仍受用户实时权限约束) |
跨资源操作同时需要两项写权限:hiring.jobState / jobAssign 需要 hiring:write + jobs:write;candidateAssign / candidatePolicy 需要 hiring:write + candidates:write。不是拿到 hiring:write 就可以修改所有资源。
以下均为请求体,POST 到标注的模块地址。ID、版本、内容都是虚构示例,不是待操作的真实记录;先从读取结果中选择真实目标。写操作的 requestId 应由客户端为每个逻辑动作生成唯一值,不能照抄示例。
POST /api/v1/hiring/tools
{
"operation": "read",
"input": {
"resource": "context",
"input": {}
}
}POST /api/v1/candidate-library/tools
{
"operation": "search",
"input": {
"query": "芯片",
"page": 1,
"pageSize": 20
}
}POST /api/v1/candidate-library/tools
{
"operation": "detail",
"input": {
"id": "1"
}
}POST /api/v1/candidate-library/tools
{
"operation": "duplicates",
"input": {
"name": "示例候选人"
}
}POST /api/v1/job-library/tools
{
"operation": "search",
"input": {
"status": "open",
"page": 1,
"pageSize": 20
}
}POST /api/v1/client-library/tools
{
"operation": "search",
"input": {
"query": "示例公司",
"page": 1,
"pageSize": 20
}
}POST /api/v1/hiring/tools
{
"operation": "read",
"input": {
"resource": "flows",
"input": {}
}
}POST /api/v1/hiring/tools
{
"operation": "read",
"input": {
"resource": "dashboard",
"input": {}
}
}POST /api/v1/hiring/tools
{
"operation": "read",
"input": {
"resource": "jobImpact",
"input": {
"jobId": 1
}
}
}POST /api/v1/candidate-library/tools
{
"operation": "note",
"input": {
"id": "1",
"content": "示例:候选人希望先了解岗位职责。",
"requestId": "example-note-001"
}
}POST /api/v1/candidate-library/tools
{
"operation": "update",
"input": {
"id": "1",
"version": 0,
"data": {
"city": "上海"
},
"requestId": "example-update-001"
}
}POST /api/v1/hiring/tools
{
"operation": "create",
"input": {
"candidateId": "1",
"jobId": 1,
"requestId": "example-flow-001"
}
}当前开放这四类工具适配器,以及候选人履历与二进制附件接口。不开放脉脉自动搜索/发送、Connector 浏览器与 Cookie、系统管理或成员迁移;不要把凭证发送到其他站点。
可见范围不等于编辑范围;管理员也看不到其他作者的私密工作台备忘和私密流程备注。拿到空列表或受限字段时如实报告,不补造数据。
业务错误格式为 {error:{code,message,details?}};飞书登录/续期协议错误格式为 {error:"...",error_description:"..."}。两者不要混淆。
| 状态 / 类型 | 建议处理 |
|---|---|
| 400 / VALIDATION_ERROR | 读取 error.details 的字段路径,重新查看实时 inputSchema,修正参数;不要原样重试。 |
| 401 / UNAUTHORIZED | 凭证可能过期、撤销或飞书身份失效。有有效 refresh_token 则尝试续期一次,否则重新发起飞书登录。 |
| 403 / FORBIDDEN | 区分 business_scope 不足和业务角色/数据权限不足。scope 不足需按任务重新登录申请;业务权限不足应停止并告知用户,换 token 不会获得管理员权限。 |
| 404 / NOT_FOUND | 可能是不存在、不可见的记录或未开放接口。不要猜 ID 或改用管理接口绕过。 |
| 409 / 冲突 | 版本、重复候选人、幂等键或岗位影响预览可能冲突。先读最新数据和错误码再决策,不要覆盖他人更新。 |
| 429 / 限流 | 遵守 Retry-After(如果提供);否则指数退避,限制重试次数,不要并发撞接口。 |
| 5xx / 暂时不可用 | 读取可有限退避重试;写入仅以相同 requestId 和相同内容重试。不要把服务异常当作登录失效。 |
超时并不等于未写入。没有确认结果时保留原 requestId,以同样请求重试;不要生成新键重复添加备注、流程或事件。若最终无法恢复,报告具体接口、操作、状态码/错误码和发生时间,不记录 token 或完整隐私文本。