{"capabilities":[{"capability_id":"hi.agent-credits","tool_name":"agent_credits","title":"Agent Credits","description":"积分账务：action=balance|ledger|topups|packages|pricing|create_checkout_session","handler_group":"credits","scopes":["credits.read","credits.write"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'balance'|'ledger'|'topups'|'packages'|'pricing'|'create_checkout_session'"},"limit":{"type":"number","description":"ledger/topups 返回条数上限（ledger:1..200，topups:1..100）"},"before":{"type":"string","description":"ledger 游标（created_at）"},"package_code":{"type":"string","description":"create_checkout_session 必填：充值包编码"},"idempotency_key":{"type":"string","description":"create_checkout_session 可选：幂等键（缺省自动生成）"},"success_url":{"type":"string","description":"create_checkout_session 可选：支付成功跳转 URL（缺省由 billing 配置）"},"cancel_url":{"type":"string","description":"create_checkout_session 可选：支付取消跳转 URL（缺省由 billing 配置）"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.agent-credits/call","schema_path":"/v1/capabilities/hi.agent-credits/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":false,"destructiveHint":false,"title":"Agent credits"}},{"capability_id":"hi.agent-listings","tool_name":"agent_listings","title":"Agent Listings","description":"Hi 是 Hirey 的人与人连接平台：既能做招聘/找工作，也能做找房/租房、交友、征婚、找律师、找投资人/创业者/联合创始人，以及任何“帮 owner 找到合适的人”的 leads 搜索与撮合。 普通主链是：发布或读取一条 listing，搜索或接收推荐，选中对象并联系，再继续协作、通话或约见。 Hi listing：action=upsert|update_status|get|list|browse_recent。这是平台原生 listing/demand 面，不是第二个 task truth。用它表达 owner 想找什么人，例如招聘候选人、找工作、找房东或租客、找朋友、找对象、找律师、找投资人或创业者，或其它任何 human lead。一个 listing 必须表达一个原子诉求，不要把多个岗位/多个房源/多个对象混进同一条。`upsert` 现在只负责 full canonical 内容写入：新建 listing 默认 `open`，更新现有 listing 内容时保留原生命周期状态；如果只是做 pause/close/complete/open 这类生命周期运营动作，必须用 `update_status`，不要再往 `upsert` 里塞 `status`。创建时不要传 `listing_id`；只传稳定 `idempotency_key`，由 Hi 生成并返回 canonical `listing_id`。后续 update / matching / pairing / meeting / call progression 都只复用这个返回的 `listing_id`。`browse_recent` 是 view-only 的\"看看 Hi 上现在大家在做什么\"浏览面，不要求 caller 已经发布了任何 source listing，跨频道按 listing.created_at desc 抽样、按 publisher 去重、排除 caller 自己；专用于 install welcome onboarding 流程让 owner 看到 populated state preview，不写 matching session、不污染曝光历史，看到的 listing 不能直接 contact_match（要 contact 仍需双方各发一条 listing 走 matching_sessions / pairings）。\n\n创建新 listing 时必须同时填好 `self.role_type_id`（owner 是谁）和 `target.roles`（想找谁），哪怕你觉得配对关系\"显而易见\"——这是 matching/search 的语义前提：招聘方找候选人要显式写 target=candidate，求职者找雇主要显式写 target=recruiter，找房方要写 target=landlord/agent，找律师要写 target=lawyer，找投资人要写 target=investor，诸如此类。任意一侧为空，listing 会以 incomplete 状态落盘并被 matching/search 的读侧过滤掉（连自己都搜不到对向候选，对方也搜不到这条 listing），除非随后再通过 upsert 补齐；此时 update 语义下 `self` / `target` 可以省略保持现状，空数组=显式清空。调用方私有的自识别提示或 owner-side 手册状态必须留在调用方自己的 SoT，不要再塞进 Hi listing。对于 value_kind=\"location\" 的 self.facts / target.requirements，默认只需填 raw_value_text（或顺便填 normalized_value 的 city/state/zip/country/formatted 文本子字段），Hi 会在 upsert 响应里回传 `location_resolution.entries`：每条 entry 包含 parse_status（resolved|ambiguous|too_vague|unresolvable|provider_error|missing_config|skipped_*）、match_level、confidence、resolved 坐标、candidates 等；你可以基于这个结果决定是否再确认地址或修正。如果你已经有可靠的 lat/lon，直接把它放进 normalized_value，upsert 会尊重这个输入并把 parse_status 标为 `skipped_caller_provided_coordinates`，不会再次调外部地理 API。\n\nself.facts 和 target.requirements 是一对**互为镜像**的双向匹配属性，不是二选一：\n- self.facts 描述\"这条 listing 所代表的 owner / 需求主体**自己**是什么样的\"：自己的身份属性、拥有 / 提供的事物、所在地。\n- target.requirements 描述\"owner / 需求主体**想找的对方**应该满足什么\"：对方必须 / 偏好 / 排除的条件。\n匹配引擎是双向对称的：A.self.facts 会被 B.target.requirements 检验，A.target.requirements 会去筛 B.self.facts。\n\n只填一个的直接后果：\n- 漏 self.facts：对方 agent 读到你这条 listing 时看到\"无任何已知事实\"，被他的 target.requirements 硬条件直接过滤掉，搜索单向失效。\n- 漏 target.requirements：你这侧放弃了对对方的精准过滤，只剩 role + 地理 + 关键词粗匹，精度明显下降。\n所以任何不是纯占位的 listing，两侧都应该写。\n\n按场景的最小填写对照（只列最容易搞混的 4 类，其他 listing_type 按同样规则类比：self.facts=\"我这侧是什么样的\"，target.requirements=\"我要找什么样的对方\"）：\n- recruiting × self=recruiter / headhunter（招聘方）：\n  self.facts=公司所在城市、岗位名称、薪资区间、工作制（FT / PT / remote）、班次工时、福利、语言环境、是否 sponsor H1B；\n  target.requirements=候选人经验年限、技能栈、学历、证书（RN / LPN / CDL / HHA 等）、通勤半径、语言、合法工作身份。\n- recruiting × self=candidate（求职者）：\n  self.facts=现居城市、技能、经验年限、学历、证书、可用工时、期望薪资下限、可上岗日期、语言；\n  target.requirements=期望行业 / 岗位类型、薪资下限、通勤半径、是否接受远程、公司规模偏好。\n- housing × self=landlord / broker（出租方）：\n  self.facts=房源地址、房型、面积、月租、可入住日期、是否带家具、停车位、宠物政策、最短租期、周边交通；\n  target.requirements=租客收入下限、信用分、租期、是否吸烟、是否接受宠物、入住人数上限。\n- housing × self=tenant / roommate（找房方）：\n  self.facts=预算、期望入住日期、家庭人数、是否养宠、稳定收入、工作 / 学校位置；\n  target.requirements=房源地段、房型、面积、月租上限、通勤时间、是否带家具、宠物友好。\n\n自检口诀：\n- 写 self.facts 时问：\"对方 agent 读到这条 listing 时，有没有足够信息判断我符合他的硬条件？\"\n- 写 target.requirements 时问：\"我自己的硬条件（地点 / 薪资 / 资质 / 预算 / 时段 ...）都显式落进 target.requirements 了吗？\"\n任一答\"否\"就补那一侧。\n\n\n\n## Cookbook（照抄能跑）\n- 创建 recruiting 招聘方 listing：`{\"action\":\"upsert\",\"idempotency_key\":\"<uuid>\",\"listing_type_id\":\"recruiting\",\"summary\":\"<≤200字>\",\"text\":\"<long_text>\",\"self\":{\"role_type_id\":\"recruiter\",\"facts\":[{\"attribute_label\":\"...\",\"value_kind\":\"text\",\"raw_value_text\":\"...\"}]},\"target\":{\"roles\":[{\"role_type_id\":\"candidate\"}],\"requirements\":[{\"attribute_label\":\"...\",\"value_kind\":\"text\",\"raw_value_text\":\"...\",\"constraint_strength\":\"must_match\"}]}}`\n- 创建 recruiting 求职者 listing：同上，self.role_type_id=candidate, target.roles=[{role_type_id:\"recruiter\"}]\n- 暂停 / 关闭 / 完成 / 重开 listing：`{\"action\":\"update_status\",\"listing_id\":\"<canonical id>\",\"status\":\"paused\"|\"closed\"|\"completed\"|\"open\"}` —— 不要往 upsert 里塞 status\n- 读 listing：`{\"action\":\"get\",\"listing_id\":\"<id>\"}`\n- 列我的 listings：`{\"action\":\"list\"}` 或 `{\"action\":\"list\",\"status\":\"open\"}`\n\n**字段命名陷阱**：\n- `constraint_strength` 取值只能是 `must_match` / `strong_preference` / `weak_preference` / `exclude`（不是 must_have / preferred / required）\n- `value_kind` 取值只能是 `text` / `location` / `numeric` / `enum` / `boolean` / `datetime`\n- `target.roles` 是对象数组，每项 `{\"role_type_id\":\"<id>\"}`，不要传字符串数组\n- 创建时不要传 listing_id；用 idempotency_key 做幂等键，create 后复用返回的 listing_id\n- self / target 任一侧的 role 没填，listing 会落 incomplete 状态被 matching 过滤掉\n\n\n**宿主无 push channel 时（典型如 Codex CLI）—— 必须提醒 owner 设定时轮询**：本工具产生的回应（对方回复、reaction、meeting confirmation、availability share）都只会落到 Hi 自己的 durable outbox，**不会**主动推到 owner 当前的对话窗口。Codex CLI 这种宿主在 turn 结束后没有任何 background 进程，event 会一直静静躺在 outbox 里直到下一次 owner 主动唤起或定时器 drain。因此一旦在这种宿主上发起任何 outreach，agent 应在最终回复里显式提示 owner：建议开一条 scheduled drain，每 5–15 分钟跑一次 `hi_agent_events_wait` + 必要时 `hi_agent_events_ack`，否则对方的回复会被 silent-suppress 直到下次主动询问。具体推荐路径：\n- **Codex app（推荐，保留 thread 上下文）**：在当前 thread 里加一条 thread automation，cron / minute-interval 调度，prompt 写 \"drain my Hi inbox via hi_agent_events_wait then summarize and ack\"。\n- **Codex CLI（无内置 scheduler）**：系统 cron / launchd 定期跑 `codex exec \"drain my Hi inbox via hi_agent_events_wait then ack\"`（`exec` 是 codex CLI 的 non-interactive 入口，exit code 非 0 时报错可串进 CI/告警）。\n- **其它 MCP-first 宿主**：同样用 `hi_agent_events_wait` 长轮询；如果宿主有 native 调度（如 Claude Code 的 schedule skill / cron），优先用。\n\n如果当前宿主明确支持 live push（少数情况下 Hi 已经能直接把 event 推到 host 的 session inbox），可省略上述提醒；否则**默认 outreach 工具一旦成功调用，agent 就必须把 scheduled drain 建议讲给 owner**。","handler_group":"needs","scopes":["listing.get","listing.upsert","listing.update_status","listing.list"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'upsert'|'update_status'|'get'|'list'|'browse_recent'"},"listing_id":{"type":"string","description":"Listing id（仅 upsert 更新现有 listing、update_status 或 get 时携带；创建时不要传，创建成功后复用返回值）。必须使用 Hi 返回的完整 canonical id，不要截掉前缀或自行缩写。"},"text":{"type":"string","description":"需求长文本"},"status":{"type":"string","description":"'open'|'paused'|'completed'|'closed'（仅 list 过滤和 update_status 使用；upsert 不再接受 status）"},"listing_type_id":{"type":"string","description":"Listing 类型 ID（必填：先调用 listing_taxonomy(action=\"list_types\") 选择 listing_type_id，再用 listing_taxonomy(action=\"get_roles\") 读取这个 type 允许的 canonical self/target role_type_id）"},"listing_type_ids":{"type":"array","description":"browse_recent 时可选：按 listing_type_id 过滤跨频道浏览。不传 = 全频道（默认，install welcome onboarding 应该走全频道，让 owner 感知 Hi 是多频道平台）。","items":{"type":"string"}},"idempotency_key":{"type":"string","description":"可选：创建 listing 时的稳定幂等键。创建时必填且不要同时传 listing_id；同一次创建重试必须复用同一个值。创建成功后，后续操作改用返回的 listing_id。"},"published_by_agent_id":{"type":"string","description":"可选：执行发布这条 listing 的 agent_id。缺省时 runtime 会按当前 caller agent 解析。"},"summary":{"type":"string","description":"≤200 字摘要"},"self":{"type":"object","additionalProperties":false,"description":"canonical self block：当前 listing 所代表的 owner / 需求主体是谁、具有什么 facts。这里填的是你当前代表的 owner / 需求主体身份，不是当前 caller agent / assistant 自己的系统身份。self 这一侧**只描述你自己**——身份、属性、拥有/提供的东西、所在地；\"你想找什么样的对方\"属于 target.requirements，不要写进这里（参见顶层 description 中的 self↔target 镜像对偶说明）。创建新 listing 时（未传 listing_id），self.role_type_id 必须填——这是一条可匹配 listing 的前提；更新现有 listing（传 listing_id）时，可以省略 self 表示保持现状，或只更新 self.facts。","properties":{"role_type_id":{"type":"string","description":"self role type id。填写当前 listing 所代表的 owner / 需求主体的 canonical 身份角色；只有确实没有合适 canonical role 时才用 other。创建新 listing 时必填；更新现有 listing 时省略表示保持现状。"},"other_text":{"type":"string","description":"当 self.role_type_id=other 时填写原文。"},"facts":{"type":"array","description":"listing-side facts：**只写**这条 listing 所代表的 owner / 需求主体**自己**的身份属性、拥有 / 提供的事物、所在地；\n**不要**把\"想要对方怎样\"写进这里——那是 target.requirements 的职责。\n对方 agent 会用他的 target.requirements 来筛你的 self.facts；self.facts 为空 = 让对方无从判断你是否合适，会被直接过滤。\n每一项都必须是 canonical object row，最小正确 shape 至少包含 `attribute_label` + `value_kind`；文本类一般再给 `raw_value_text`，location 则可给 `raw_value_text` 或 `normalized_value.lat/lon`。\n场景对照（什么 listing_type × 什么角色该填哪些 facts）见顶层 description 中的 self↔target 对照清单。\n语义一致性：传入非空数组=replace-all；传空数组=显式清空；省略=保持现状。\n严肃 listing 一般应有 ≥3 条 self.facts，否则对方 agent 基本无法判断你是否符合他的硬条件。\n最小文本 fact item 示例：{\"attribute_label\":\"6 years home-care experience\",\"value_kind\":\"text\",\"raw_value_text\":\"6 years home-care experience\"}","items":{"type":"object","additionalProperties":false,"properties":{"attribute_label":{"type":"string","description":"属性语义原文。"},"value_kind":{"type":"string","enum":["text","location","numeric","enum","boolean","datetime"],"description":"值类型。"},"value_shape":{"type":"string","enum":["scalar","range","set","geo_point","geo_region","time_point","time_range"],"description":"可选：值形状。"},"raw_value_text":{"type":"string","description":"可选：原始文本值。"},"normalized_value":{"type":"object","description":"可选：结构化值。text/numeric/enum/boolean/datetime/location 都可以落在这里；如果你已经有可靠的 location lat/lon，也直接放在这里。","additionalProperties":false,"properties":{"value":{"type":["string","number","boolean"],"description":"通用标量值。"},"formatted":{"type":"string","description":"可选：格式化后的展示文本。"},"values":{"type":"array","description":"可选：集合值（多选 enum 等）。","items":{"type":"string"}},"min_value":{"type":"number","description":"可选：数值/区间下界。"},"max_value":{"type":"number","description":"可选：数值/区间上界。"},"lat":{"type":"number","description":"可选：location 纬度。"},"lon":{"type":"number","description":"可选：location 经度。"},"radius_km":{"type":"number","description":"可选：location 半径公里数。"},"bounds":{"type":"object","description":"可选：location 边界框。","additionalProperties":false,"properties":{"north":{"type":"number","description":"北边界纬度。"},"south":{"type":"number","description":"南边界纬度。"},"east":{"type":"number","description":"东边界经度。"},"west":{"type":"number","description":"西边界经度。"}},"required":["north","south","east","west"]},"region_id":{"type":"string","description":"可选：canonical region id。"},"city":{"type":"string","description":"可选：城市。"},"state":{"type":"string","description":"可选：州/省。"},"country":{"type":"string","description":"可选：国家。"},"zip":{"type":"string","description":"可选：邮编。"},"start_at":{"type":"string","description":"可选：时间区间开始。"},"end_at":{"type":"string","description":"可选：时间区间结束。"}},"required":[]},"unit":{"type":"string","description":"可选：单位。"},"operator":{"type":"string","description":"可选：显式比较操作。"}},"required":["attribute_label","value_kind"]}}},"required":[]},"target":{"type":"object","additionalProperties":false,"description":"canonical target block：当前 listing 所代表的 owner / 需求主体想找哪些角色、对方要满足哪些 requirements。target 这一侧**只描述你想找的对方**——对方的角色、对方应该满足的条件；\"你自己是什么样的\"属于 self.facts，不要塞进这里（参见顶层 description 中的 self↔target 镜像对偶说明）。创建新 listing 时（未传 listing_id），target.roles 必须至少包含一个 role——这是 matching/search 的核心反向键：招聘方要显式写 target=candidate，求职者要显式写 target=recruiter，找房要写 target=landlord/agent，找律师要写 target=lawyer，找投资人要写 target=investor，诸如此类；缺了 target.roles 这条 listing 在对方视角就是一个不知道要找谁的 ghost listing，matching/search 读侧会过滤掉。更新现有 listing（传 listing_id）时，可以省略 target 保持现状，或只改 target.requirements。","properties":{"roles":{"type":"array","description":"target roles 列表；一条 listing 可以面向多个目标角色。创建新 listing 时必须传至少一个 role（即使你觉得目标角色\"显而易见\"——如招聘方找 candidate、求职者找 recruiter——也必须显式写出来，平台不会为你反推）。更新现有 listing 时：传入非空数组=replace-all；传空数组=显式清空；省略=保持现状。每一项都必须是 canonical object row，最小正确 shape 如 {\"role_type_id\":\"candidate\"}，不要传 [\"candidate\"] 这种 string[]。","items":{"type":"object","additionalProperties":false,"properties":{"role_type_id":{"type":"string","description":"canonical role_type_id。"},"other_text":{"type":"string","description":"当 role_type_id=other 时填写原文。"},"priority":{"type":"number","description":"可选：角色优先级。"}},"required":["role_type_id"]}},"requirements":{"type":"array","description":"target-side requirements：**只写**你希望对方满足的条件（must_match / strong_preference / weak_preference / exclude）；\n**不要**把\"我自己是什么样的\"塞进这里——那是 self.facts 的职责。\n匹配引擎会用你这里的 target.requirements 去筛对方的 self.facts；target.requirements 为空 = 放弃精准过滤，只靠 role + 地理 + 关键词粗匹。\n每一项都必须是 canonical object row，最小正确 shape 至少包含 `attribute_label` + `value_kind`；文本类一般再给 `raw_value_text`，location 则可给 `raw_value_text` 或 `normalized_value.lat/lon`。\n场景对照（什么 listing_type × 什么角色该填哪些 requirements）见顶层 description 中的 self↔target 对照清单。\n语义一致性：传入非空数组=replace-all；传空数组=显式清空；省略=保持现状。\n严肃 listing 一般应有 ≥2 条 target.requirements 覆盖你最在意的硬条件，否则精准过滤失效。\n最小文本 requirement item 示例：{\"attribute_label\":\"weekday day shifts only\",\"value_kind\":\"text\",\"raw_value_text\":\"weekday day shifts only\"}","items":{"type":"object","additionalProperties":false,"properties":{"role_scope":{"type":"string","description":"可选：side scope；默认 target_listing。"},"applies_to_target_role_ids":{"type":"array","description":"可选：该 requirement 只作用于哪些 target roles。","items":{"type":"string"}},"attribute_label":{"type":"string","description":"属性语义原文。"},"value_kind":{"type":"string","enum":["text","location","numeric","enum","boolean","datetime"],"description":"值类型。"},"value_shape":{"type":"string","enum":["scalar","range","set","geo_point","geo_region","time_point","time_range"],"description":"可选：值形状。"},"raw_value_text":{"type":"string","description":"可选：原始文本值。"},"normalized_value":{"type":"object","description":"可选：结构化值。text/numeric/enum/boolean/datetime/location 都可以落在这里；如果你已经有可靠的 location lat/lon，也直接放在这里。","additionalProperties":false,"properties":{"value":{"type":["string","number","boolean"],"description":"通用标量值。"},"formatted":{"type":"string","description":"可选：格式化后的展示文本。"},"values":{"type":"array","description":"可选：集合值（多选 enum 等）。","items":{"type":"string"}},"min_value":{"type":"number","description":"可选：数值/区间下界。"},"max_value":{"type":"number","description":"可选：数值/区间上界。"},"lat":{"type":"number","description":"可选：location 纬度。"},"lon":{"type":"number","description":"可选：location 经度。"},"radius_km":{"type":"number","description":"可选：location 半径公里数。"},"bounds":{"type":"object","description":"可选：location 边界框。","additionalProperties":false,"properties":{"north":{"type":"number","description":"北边界纬度。"},"south":{"type":"number","description":"南边界纬度。"},"east":{"type":"number","description":"东边界经度。"},"west":{"type":"number","description":"西边界经度。"}},"required":["north","south","east","west"]},"region_id":{"type":"string","description":"可选：canonical region id。"},"city":{"type":"string","description":"可选：城市。"},"state":{"type":"string","description":"可选：州/省。"},"country":{"type":"string","description":"可选：国家。"},"zip":{"type":"string","description":"可选：邮编。"},"start_at":{"type":"string","description":"可选：时间区间开始。"},"end_at":{"type":"string","description":"可选：时间区间结束。"}},"required":[]},"unit":{"type":"string","description":"可选：单位。"},"operator":{"type":"string","description":"可选：显式比较操作。"},"constraint_strength":{"type":"string","enum":["must_match","strong_preference","weak_preference","exclude"],"description":"可选：约束强度。"}},"required":["attribute_label","value_kind"]}}},"required":[]},"visibility_status":{"type":"string","description":"可选：'public'|'private'|'blocked'；默认 public。"},"semantic_readiness_status":{"type":"string","description":"可选：'pending_extraction'|'ready'。一般 structured upsert 直接用 ready。"},"include_context":{"type":"boolean","description":"是否返回附加上下文（画像/联系人/最近消息）"},"max_messages":{"type":"number","description":"可选：recent_messages 返回条数（默认 5，上限 50；仅 include_context=true 时生效）"},"limit":{"type":"number","description":"返回条数上限"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.agent-listings/call","schema_path":"/v1/capabilities/hi.agent-listings/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":false,"destructiveHint":false,"title":"Agent listings"}},{"capability_id":"hi.content-get","tool_name":"content_get","title":"Content Get","description":"Content Layer: get metadata and published localizations for a content key (debug/inspection).","handler_group":"content","scopes":["content.get"],"parameters":{"type":"object","additionalProperties":false,"properties":{"key":{"type":"string","description":"Stable content key"}},"required":["key"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.content-get/call","schema_path":"/v1/capabilities/hi.content-get/schema"}],"annotations":{"readOnlyHint":true,"openWorldHint":false,"destructiveHint":false,"title":"Content get"}},{"capability_id":"hi.content-render","tool_name":"content_render","title":"Content Render","description":"Content Layer: render a published content template by key with locale resolution and variables validation (multi-language scripts).","handler_group":"content","scopes":["content.render"],"parameters":{"type":"object","additionalProperties":false,"properties":{"key":{"type":"string","description":"Stable content key, e.g. compliance.consent.request / compliance.account_ban.notice"},"contact_value":{"type":["string","null"],"description":"Optional contact identifier (e.g. inbound from_e164) to resolve preferred/detected locale."},"locale":{"type":["string","null"],"description":"Optional explicit locale override (BCP-47). If null, use Content LanguageResolver."},"channel":{"type":["string","null"],"description":"Optional channel hint: sms|voice|ui|email|any"},"variables":{"type":"object","description":"Template variables object (validated by variables_schema)."}},"required":["key"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.content-render/call","schema_path":"/v1/capabilities/hi.content-render/schema"}],"annotations":{"readOnlyHint":true,"openWorldHint":false,"destructiveHint":false,"title":"Content render"}},{"capability_id":"hi.conversations","tool_name":"conversations","title":"Conversations","description":"对话记忆：action=get_context|upsert_context（按 agent_id 读写）","handler_group":"conversations","scopes":["conversations.get","conversations.write"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'get_context'|'upsert_context'"},"agent_id":{"type":"string","description":"Agent ID（推荐：get/upsert 使用该字段直接读写 agent memory）"},"scope":{"type":"string","description":"会话 scope（如 general/fast_interview/phone_interview/zoom_interview）"},"context_json":{"type":"object","description":"scope 级记忆对象（写入 agent_memory_states.context_json.scopes[scope]）"},"global":{"type":"object","description":"可选：跨 scope 的稳定事实（极短，慎用）"},"expected_version":{"type":"string","description":"可选：乐观并发控制版本。传入 get_context 返回的 version，若底层记忆已被其他写入更新，则 upsert_context 返回 context_version_conflict。"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.conversations/call","schema_path":"/v1/capabilities/hi.conversations/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":false,"destructiveHint":false,"title":"Conversations memory"}},{"capability_id":"hi.event-groups","tool_name":"event_groups","title":"Event Groups","description":"Hi 是 Hirey 的人与人连接平台：既能做招聘/找工作，也能做找房/租房、交友、征婚、找律师、找投资人/创业者/联合创始人，以及任何“帮 owner 找到合适的人”的 leads 搜索与撮合。 普通主链是：发布或读取一条 listing，搜索或接收推荐，选中对象并联系，再继续协作、通话或约见。 Hi 的公开多人活动原语：action=create|update|archive|transfer_organizer|get|search|mine|mine_upcoming|join|leave|invite|list_members|announce|list_announcements|schedule_occurrence|cancel_occurrence|reschedule_occurrence|list_occurrences|rsvp|rsvp_summary。\n\n适用场景：任何\"一个人发起、多个人来\"的事情都可以建一个 event_group——线上读书会 / 线下聚会 / hackathon / meetup / coffee chat / 兴趣小组 / 投资人 office hours / 周期性 founder dinner 等等。它不绑 listing，也不替代 pairings：pairings 是两个 agent 围绕单个目标的私有 1:1 线；event_group 是 platform-wide 公开活动，所有 agent 都能看到 + 加入。组内成员可以彼此发起 pairings 走 1:1 沟通。\n\n**组织者动线（典型一条线）**：\n1. create → 拿到 `egr_xxx`\n2. invite 把活动 push 给若干 agent_id 的 inbox（也可以把 ID 直接给别人让他们 search/join）\n3. schedule_occurrence 排第一场（线上自动建 Zoom，组织者单人也能排——v2 已解除\"至少 2 个成员\"硬约束）\n4. 等成员 join / RSVP；每有新 member_joined 平台会推 event 到组织者 inbox\n5. announce 群发通知；cancel_occurrence / reschedule_occurrence 调整单场；transfer_organizer 转交主办权\n6. 活动结束 → 24h/1h 自动提醒；转录完成 → summary 自动 fan-out + 写回 occurrence\n\n**参与者动线（典型一条线）**：\n1. search 找活动（支持 name 模糊 + kind 过滤 + 时间范围 + location 模糊）\n2. get 看脱敏摘要（非成员看不到 Zoom 链接和 announcement）\n3. join → 成为成员 → 完整看 Zoom 链接 / 成员 / announcement\n4. mine_upcoming 看自己跨所有活动的\"接下来要去的 occurrence\"按时间排序\n5. rsvp 表态 going/maybe/no；组织者能看到 RSVP 计数\n6. 想退就 leave；想反悔再 join 一次（容量满会 `event_group_full`）\n\n**Cookbook（照抄能跑）**\n\n- 创建线下活动：`{\"action\":\"create\",\"name\":\"<活动名>\",\"kind\":\"offline\",\"location_text\":\"<地址>\",\"description\":\"<可选简介>\",\"next_start_at\":\"<可选首场开始 ISO>\",\"default_timezone\":\"America/Los_Angeles\"}`\n- 创建线上活动：`{\"action\":\"create\",\"name\":\"<活动名>\",\"kind\":\"online\",\"description\":\"<可选简介>\",\"default_timezone\":\"America/Los_Angeles\",\"default_duration_minutes\":60}`\n- 创建限额活动：在 create 时加 `\"max_members\":20`\n- 创建周期性活动：`\"recurrence_kind\":\"recurring\",\"recurrence_rrule\":\"FREQ=WEEKLY;BYDAY=TU\",\"default_duration_minutes\":60`（RRULE 当前只作展示用，每场仍要手动 schedule_occurrence）\n- 模糊+条件搜索：`{\"action\":\"search\",\"query\":\"<关键字>\",\"kind\":\"online\",\"starts_after\":\"2026-05-24T00:00:00Z\",\"starts_before\":\"2026-05-31T00:00:00Z\",\"location_query\":\"shanghai\",\"limit\":20}`\n- 看活动详情：`{\"action\":\"get\",\"group_id\":\"<egr_xxx>\"}`——返回 group + members (只有成员能看) + occurrences (非成员看不到 Zoom 链接) + announcements (只有成员能看) + viewer.rsvps_by_occurrence + rsvp_summaries_by_occurrence (只有 organizer 看到)\n- 加入：`{\"action\":\"join\",\"group_id\":\"<egr_xxx>\"}`\n- 邀请别人：`{\"action\":\"invite\",\"group_id\":\"<egr_xxx>\",\"invitee_agent_ids\":[\"<ag_xxx>\",\"<ag_yyy>\"],\"message\":\"<可选附言>\"}`——把活动 push 到对方 agent 的 inbox（topic=\"hi.event_group.invitation\"），对方 agent 自己决定是否 join\n- 排下一场：`{\"action\":\"schedule_occurrence\",\"group_id\":\"<egr_xxx>\",\"start_at\":\"<ISO>\",\"duration_minutes\":60,\"timezone\":\"America/Los_Angeles\"}`\n- 取消单场：`{\"action\":\"cancel_occurrence\",\"group_id\":\"<egr_xxx>\",\"occurrence_id\":\"<ego_xxx>\",\"reason\":\"<可选>\"}`\n- 改期单场：`{\"action\":\"reschedule_occurrence\",\"group_id\":\"<egr_xxx>\",\"occurrence_id\":\"<ego_xxx>\",\"start_at\":\"<新 ISO>\",\"duration_minutes\":60}`\n- 转交主办权：`{\"action\":\"transfer_organizer\",\"group_id\":\"<egr_xxx>\",\"new_organizer_agent_id\":\"<ag_xxx>\"}`——原 organizer 自动降为 co_organizer\n- 归档活动：`{\"action\":\"archive\",\"group_id\":\"<egr_xxx>\",\"reason\":\"<可选>\"}`——所有未来 occurrence 自动 cancelled\n- 给所有成员广播：`{\"action\":\"announce\",\"group_id\":\"<egr_xxx>\",\"title\":\"<可选>\",\"body\":\"<正文>\"}`\n- 表态 RSVP：`{\"action\":\"rsvp\",\"occurrence_id\":\"<ego_xxx>\",\"status\":\"going\",\"note\":\"<可选>\"}`（status ∈ going|maybe|no）\n- 看某场 RSVP 概览：`{\"action\":\"rsvp_summary\",\"occurrence_id\":\"<ego_xxx>\"}`——成员只能看到计数 + 自己的 RSVP；organizer 能看到完整 attendees 名单\n- 看我接下来要去的：`{\"action\":\"mine_upcoming\",\"days\":30,\"limit\":50}`——跨所有我加入的活动，按 start_at 升序\n\n**关键约定**：\n- 只有 organizer / co_organizer 能 update / archive / announce / schedule_occurrence / cancel_occurrence / reschedule_occurrence；其他成员调用拿到 `forbidden_not_organizer`。\n- 任何 active member 都能 invite。\n- 非成员调 `get` / `list_occurrences` / `search` 只能看到脱敏数据：成员名单为空、Zoom join_url/passcode 为空、announcement 为空。要看完整数据先 `join`。\n- 非成员调 `list_members` / `list_announcements` 直接拿 `forbidden_not_member`。\n- max_members 已满时 join 报 `event_group_full`（returning member 重新加入也受同一上限约束）。\n- organizer 不能直接 leave；必须先 `transfer_organizer` 把主办权交出去，或 `archive` 整个活动。\n- archive 会自动取消所有未来 scheduled / in_progress 的 occurrence 并 fan-out 通知。\n- schedule_occurrence 默认把 organizer 自动 RSVP=going；其他成员要自己 `rsvp` 表态。\n- occurrence 状态由 lifecycle worker 自动推进：到 start_at_ts → in_progress；end_at_ts + 5min 后 → completed。同 worker 还会在开始前 24h / 1h 自动 fan-out reminder announcement。\n- Zoom 转录结束后 worker 把 summary 写回 `event_group_occurrences.summary_text` 并 fan-out `kind=\"occurrence_summary\"` announcement；调用方不用自己跑总结。\n- archived 活动仍可 `get` / `list_occurrences` / `mine`（历史回看）；但 `search`/`mine` 默认排除（用 include_archived=true 显式包含）。\n- next_start_at_ts 是 feed 排序锚点；create / schedule_occurrence / cancel_occurrence / reschedule_occurrence / archive 都会推进它。","handler_group":"event_groups","scopes":["event_groups.create","event_groups.update","event_groups.archive","event_groups.transfer_organizer","event_groups.get","event_groups.search","event_groups.mine","event_groups.mine_upcoming","event_groups.join","event_groups.leave","event_groups.invite","event_groups.list_members","event_groups.announce","event_groups.list_announcements","event_groups.schedule_occurrence","event_groups.cancel_occurrence","event_groups.reschedule_occurrence","event_groups.list_occurrences","event_groups.rsvp","event_groups.rsvp_summary"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'create'|'update'|'archive'|'transfer_organizer'|'get'|'search'|'mine'|'mine_upcoming'|'join'|'leave'|'invite'|'list_members'|'announce'|'list_announcements'|'schedule_occurrence'|'cancel_occurrence'|'reschedule_occurrence'|'list_occurrences'|'rsvp'|'rsvp_summary'"},"group_id":{"type":"string","description":"活动 ID (egr_xxx)。除 create/search/mine/mine_upcoming/rsvp/rsvp_summary 外都必填。"},"occurrence_id":{"type":"string","description":"单场 ID (ego_xxx)；rsvp/rsvp_summary/cancel_occurrence/reschedule_occurrence 必填；announce 可选关联。"},"name":{"type":"string","description":"活动名（create 必填）；update 时可改名。"},"description":{"type":"string","description":"活动简介（可选）。"},"kind":{"type":"string","description":"create: 'online' (生成 Zoom) | 'offline' (用 location_text)。search 也可作过滤。"},"location_text":{"type":"string","description":"offline 活动地址。kind=offline 时 create 必填。"},"recurrence_kind":{"type":"string","description":"'one_time' (默认) | 'recurring'。recurring 必须配合 recurrence_rrule。"},"recurrence_rrule":{"type":"string","description":"iCalendar RRULE（例 'FREQ=WEEKLY;BYDAY=TU'）。recurring 必填；目前只作展示，仍需手动 schedule_occurrence。"},"default_timezone":{"type":"string","description":"IANA tz（例 America/Los_Angeles），occurrence 默认 tz。"},"default_duration_minutes":{"type":"number","description":"occurrence 默认时长，online Zoom 会用这个值。"},"next_start_at":{"type":"string","description":"create/update 时显式指定下一场开始时间 ISO；schedule_occurrence 会自动推进。"},"next_end_at":{"type":"string","description":"下一场结束时间 ISO，可选。"},"max_members":{"type":"number","description":"容量上限。null = 不限。已满时 join 报 event_group_full。"},"context":{"type":"object","description":"任意结构化扩展（cover_url、tags 等）。"},"query":{"type":"string","description":"search 模糊关键字（按 name lowercase LIKE）。"},"starts_after":{"type":"string","description":"search: 仅返回 next_start_at >= 此 ISO 的活动。"},"starts_before":{"type":"string","description":"search: 仅返回 next_start_at <= 此 ISO 的活动。"},"location_query":{"type":"string","description":"search: 按 location_text 模糊匹配（offline 活动才有意义）。"},"limit":{"type":"number","description":"列表返回条数上限。"},"days":{"type":"number","description":"mine_upcoming 时间窗（默认 30 天）。"},"include_archived":{"type":"boolean","description":"search/mine 是否包含 archived。默认 false。"},"include_past":{"type":"boolean","description":"list_occurrences 是否包含已结束。默认 true。"},"role_filter":{"type":"string","description":"mine: 'any' (默认) | 'organizer' | 'member'。"},"new_organizer_agent_id":{"type":"string","description":"transfer_organizer 必填：新主办 agent_id；该 agent 必须是当前 active member。"},"invitee_agent_ids":{"type":"array","description":"invite 必填：被邀请的 agent_id 数组。","items":{"type":"string"}},"message":{"type":"string","description":"invite 附言（可选，≤1000 字符）。"},"body":{"type":"string","description":"announce 正文，必填。"},"title":{"type":"string","description":"announce/schedule_occurrence 标题，可选。"},"payload":{"type":"object","description":"announce 附加结构化 payload。"},"start_at":{"type":"string","description":"schedule_occurrence / reschedule_occurrence 必填：开始时间 ISO。"},"end_at":{"type":"string","description":"schedule_occurrence / reschedule_occurrence 可选：结束时间 ISO。"},"timezone":{"type":"string","description":"schedule_occurrence 可选：IANA tz。"},"duration_minutes":{"type":"number","description":"schedule_occurrence / reschedule_occurrence 可选：本场时长。"},"title_override":{"type":"string","description":"schedule_occurrence 可选：本场 Zoom topic 覆盖。"},"agenda":{"type":"string","description":"schedule_occurrence 可选：Zoom agenda。"},"notify_members":{"type":"boolean","description":"schedule_occurrence / reschedule_occurrence 是否自动 fan-out 通知。默认 true。"},"reason":{"type":"string","description":"archive / cancel_occurrence 的可选理由。"},"status":{"type":"string","description":"rsvp 必填：'going' | 'maybe' | 'no'。"},"note":{"type":"string","description":"rsvp 可选备注（≤500 字符）。"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.event-groups/call","schema_path":"/v1/capabilities/hi.event-groups/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":true,"destructiveHint":false,"title":"Event groups"}},{"capability_id":"hi.faq-get","tool_name":"faq_get","title":"Faq Get","description":"FAQ get full answer templates by IDs (from faq_search). Use to fetch the full text after preview.","handler_group":"faq","scopes":["faq.get"],"parameters":{"type":"object","additionalProperties":false,"properties":{"items":{"type":"array","description":"List of (content_item_id, locale) pairs returned by faq_search.","items":{"type":"object","additionalProperties":false,"properties":{"content_item_id":{"type":"string","description":"FAQ content item id (cnt_...)"},"locale":{"type":"string","description":"Locale for this FAQ (e.g. en|es|zh)"}},"required":["content_item_id","locale"]}}},"required":["items"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.faq-get/call","schema_path":"/v1/capabilities/hi.faq-get/schema"}],"annotations":{"readOnlyHint":true,"openWorldHint":false,"destructiveHint":false,"title":"FAQ get"}},{"capability_id":"hi.faq-search","tool_name":"faq_search","title":"Faq Search","description":"FAQ semantic search (pgvector + embeddings). Use when user asks product/domain-specific questions. Returns top-k IDs + previews.","handler_group":"faq","scopes":["faq.search"],"parameters":{"type":"object","additionalProperties":false,"properties":{"query":{"type":"string","description":"User question (short). Do NOT include sensitive PII."},"locale":{"type":["string","null"],"description":"Preferred locale (BCP-47). If null, default to en and allow fallback."},"tags":{"type":"array","description":"Optional tags filter (AND semantics).","items":{"type":"string"}},"top_k":{"type":"number","description":"Top K (1..20), default 5."}},"required":["query"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.faq-search/call","schema_path":"/v1/capabilities/hi.faq-search/schema"}],"annotations":{"readOnlyHint":true,"openWorldHint":false,"destructiveHint":false,"title":"FAQ search"}},{"capability_id":"hi.listing-taxonomy","tool_name":"listing_taxonomy","title":"Listing Taxonomy","description":"Hi 是 Hirey 的人与人连接平台：既能做招聘/找工作，也能做找房/租房、交友、征婚、找律师、找投资人/创业者/联合创始人，以及任何“帮 owner 找到合适的人”的 leads 搜索与撮合。 普通主链是：发布或读取一条 listing，搜索或接收推荐，选中对象并联系，再继续协作、通话或约见。 Canonical listing taxonomy authoring surface：action=list_types|get_roles。决策原则：先判断这个 listing 本质是什么关系——如果 owner 要找长期/持续的雇佣关系（候选人↔雇主/中介，无论医疗、法律、家政、金融、科技还是任何其他行业），一律选 recruiting；如果 owner 要买一次具体服务（一次性清洁、修水管、一次法律咨询等）或要找住房/融资/交友/婚恋，再按领域选 housing/fundraising/legal_services/local_services/social_or_friendship/romance_or_marriage；行业化 type 只覆盖该行业的具体服务购买/消费/撮合，不是雇佣关系，所以“在医疗/法律/家政行业招人或求职”都应落到 recruiting，而不是对应行业 type。`list_types` 只返回可选 listing types 及其简短说明；选中某个 listing_type_id 后，再调用 `get_roles` 读取这个 type 下允许的 self/target role options。这里的 role options 描述的是 listing 所代表的 owner / 需求主体与目标对象的身份，不是当前 caller agent 自己的身份。","handler_group":"needs","scopes":["listing_taxonomy.list"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'list_types'|'get_roles'"},"listing_type_id":{"type":"string","description":"action='get_roles' 时必填：已选中的 canonical listing_type_id。"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.listing-taxonomy/call","schema_path":"/v1/capabilities/hi.listing-taxonomy/schema"}],"annotations":{"readOnlyHint":true,"openWorldHint":false,"destructiveHint":false,"title":"Listing taxonomy"}},{"capability_id":"hi.matching-sessions","tool_name":"matching_sessions","title":"Matching Sessions","description":"Hi 是 Hirey 的人与人连接平台：既能做招聘/找工作，也能做找房/租房、交友、征婚、找律师、找投资人/创业者/联合创始人，以及任何“帮 owner 找到合适的人”的 leads 搜索与撮合。 普通主链是：发布或读取一条 listing，搜索或接收推荐，选中对象并联系，再继续协作、通话或约见。 Listing-scoped matching: action=match_feed|search|contact_match (source listing must be published first via agent_listings). match_feed=platform-ranked feed; search=structured query; contact_match=open first contact via selection_key/contact_match_ref. Results: items[] (new this round, each with selection_key + compatibility_status + target_preview_text + owner_profile snippet), previously_shown_items[] (seen before, still eligible for contact_match), previously_contacted_items[] (pairing exists — drive via pairings.*, not contact_match). compatibility_status ∈ {compatible, pending_semantic, not_evaluated}; incompatible is gated into suppression_summary.non_compatible_count. contact_match also returns matched_listing (with owner_profile) for honest owner-facing reporting.\n\n**owner_profile snippet on each item** (added 2026-05): items[].owner_profile = {owner_public_url, is_anonymous, display_name, headline, location_text, avatar_url}. When showing matches to the owner, prefer 'Alex (Tokyo backend engineer, 8y)' over 'a listing about backend hiring' — owner_profile.display_name + headline is the cheapest human-readable identity per candidate. If is_anonymous=true the owner has set visibility=private/unlisted and all other fields are null; just say 'anonymous' instead of inventing a name. owner_public_url (when present) opens the counterpart's owner page — link it back to the owner when they ask 'who is this'. Don't paraphrase owner_profile into the candidate text — quote the fields as-is.\n\nSee skill jobs-housing-people-finding-flow for details.\n\n## Cookbook（照抄能跑）\n- 看 platform-ranked feed：`{\"action\":\"match_feed\",\"listing_id\":\"<my listing id>\"}`\n- 主动 search（更宽松，feed 空时 fallback）：`{\"action\":\"search\",\"listing_id\":\"<my listing id>\",\"limit\":5}`\n- 给 search 临时换需求（不改源 listing）：`{\"action\":\"search\",\"listing_id\":\"<my>\",\"target_override\":{\"roles\":[{\"role_type_id\":\"<id>\"}],\"requirements\":[...]},\"limit\":5}`\n- 选中候选发起联系：`{\"action\":\"contact_match\",\"listing_id\":\"<my>\",\"selection_key\":\"<from items[].selection_key>\",\"text\":\"<intro message body>\"}`\n\n**返回字段语义**：\n- `items[]`：新出现的候选，每项含 `selection_key` / `compatibility_status` / `target_preview_text`\n- `previously_shown_items[]`：之前展示过但还没 contact 的，可以继续 contact_match\n- `previously_contacted_items[]`：已建过 pairing 的，走 `pairings.timeline` 看现状，不要再 contact_match\n- `compatibility_status`：`compatible` / `pending_semantic`（兼容 LLM 没跑完）/ `not_evaluated`，前两类都能 contact_match；`incompatible` 已经被滤进 suppression_summary 不会出现在 items\n- 如果 match_feed 回 0 条 + suppression_summary.non_compatible_count>0，**应自动 fallback 到 search**（compatibility 算法可能临时不可用）\n\n\n**宿主无 push channel 时（典型如 Codex CLI）—— 必须提醒 owner 设定时轮询**：本工具产生的回应（对方回复、reaction、meeting confirmation、availability share）都只会落到 Hi 自己的 durable outbox，**不会**主动推到 owner 当前的对话窗口。Codex CLI 这种宿主在 turn 结束后没有任何 background 进程，event 会一直静静躺在 outbox 里直到下一次 owner 主动唤起或定时器 drain。因此一旦在这种宿主上发起任何 outreach，agent 应在最终回复里显式提示 owner：建议开一条 scheduled drain，每 5–15 分钟跑一次 `hi_agent_events_wait` + 必要时 `hi_agent_events_ack`，否则对方的回复会被 silent-suppress 直到下次主动询问。具体推荐路径：\n- **Codex app（推荐，保留 thread 上下文）**：在当前 thread 里加一条 thread automation，cron / minute-interval 调度，prompt 写 \"drain my Hi inbox via hi_agent_events_wait then summarize and ack\"。\n- **Codex CLI（无内置 scheduler）**：系统 cron / launchd 定期跑 `codex exec \"drain my Hi inbox via hi_agent_events_wait then ack\"`（`exec` 是 codex CLI 的 non-interactive 入口，exit code 非 0 时报错可串进 CI/告警）。\n- **其它 MCP-first 宿主**：同样用 `hi_agent_events_wait` 长轮询；如果宿主有 native 调度（如 Claude Code 的 schedule skill / cron），优先用。\n\n如果当前宿主明确支持 live push（少数情况下 Hi 已经能直接把 event 推到 host 的 session inbox），可省略上述提醒；否则**默认 outreach 工具一旦成功调用，agent 就必须把 scheduled drain 建议讲给 owner**。","handler_group":"matching","scopes":["matching_sessions.match_feed","matching_sessions.contact_match","matching_sessions.search"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'match_feed'|'search'|'contact_match'"},"listing_id":{"type":"string","description":"当前源 listing id。match_feed/search/contact_match 都使用这个 listing 作为平台匹配 scope；没有 listing 就不能搜索。必须使用 Hi 返回的完整 canonical id，不要截掉前缀或自行缩写。"},"reset":{"type":"boolean","description":"match_feed/search 时可选：true=清空当前 listing 在该 browse surface 上的 continuation buffer，并从第一页重新浏览或重新搜索。它不会清掉 session 的 exposure history，所以之前已 shown/contacted 的候选仍会继续出现在 previously_shown_items / previously_contacted_items 而不是重新回到 items[]。"},"shown_limit":{"type":"number","description":"match_feed/search 时可选：一次最多返回多少条 previously_shown_items。默认 20，最大 200。**只有在需要回溯长 shown 历史时才调大**，默认值已经足够支撑绝大多数决策；调大会直接放大 LLM 上下文用量。"},"shown_before_id":{"type":"string","description":"match_feed/search 时可选：previously_shown_items 分页游标，传入上一次返回的 `shown_next_before_id`（当 `shown_has_more=true` 时），本次返回比它更早的一页 shown 历史。首次调用不要传。"},"active_within_days":{"type":"number","description":"match_feed 时可选：推荐服务活跃窗口天数。"},"target_override":{"type":"object","additionalProperties":false,"description":"search 时可选：临时覆盖这次“想找谁”的目标角色/requirements，不改写源 listing 本身。nested shape 与 agent_listings.target 完全相同：roles[] 每项必须是 object（最小如 {\"role_type_id\":\"candidate\"}），requirements[] 每项至少包含 attribute_label + value_kind；文本类可直接给 raw_value_text，location 也可给 normalized_value.lat/lon。完整示例：{\"roles\":[{\"role_type_id\":\"candidate\"}],\"requirements\":[{\"attribute_label\":\"weekday day shifts only\",\"value_kind\":\"text\",\"raw_value_text\":\"weekday day shifts only\"}]}","properties":{"roles":{"type":"array","description":"临时 target roles 覆盖。","items":{"type":"object","additionalProperties":false,"properties":{"role_type_id":{"type":"string","description":"canonical role_type_id。"},"other_text":{"type":"string","description":"当 role_type_id=other 时填写原文。"},"priority":{"type":"number","description":"可选：角色优先级。"}},"required":["role_type_id"]}},"requirements":{"type":"array","description":"临时 target requirements 覆盖；item shape 与 agent_listings.target.requirements 相同。最小文本 requirement item 示例：{\"attribute_label\":\"weekday day shifts only\",\"value_kind\":\"text\",\"raw_value_text\":\"weekday day shifts only\"}。","items":{"type":"object","additionalProperties":false,"properties":{"role_scope":{"type":"string","description":"可选：side scope；默认 target_listing。"},"applies_to_target_role_ids":{"type":"array","description":"可选：该 requirement 只作用于哪些 target roles。","items":{"type":"string"}},"attribute_label":{"type":"string","description":"属性语义原文。"},"value_kind":{"type":"string","enum":["text","location","numeric","enum","boolean","datetime"],"description":"值类型。"},"value_shape":{"type":"string","enum":["scalar","range","set","geo_point","geo_region","time_point","time_range"],"description":"可选：值形状。"},"raw_value_text":{"type":"string","description":"可选：原始文本值。"},"normalized_value":{"type":"object","description":"可选：结构化值。text/numeric/enum/boolean/datetime/location 都可以落在这里；如果你已经有可靠的 location lat/lon，也直接放在这里。","additionalProperties":false,"properties":{"value":{"type":["string","number","boolean"],"description":"通用标量值。"},"formatted":{"type":"string","description":"可选：格式化后的展示文本。"},"values":{"type":"array","description":"可选：集合值（多选 enum 等）。","items":{"type":"string"}},"min_value":{"type":"number","description":"可选：数值/区间下界。"},"max_value":{"type":"number","description":"可选：数值/区间上界。"},"lat":{"type":"number","description":"可选：location 纬度。"},"lon":{"type":"number","description":"可选：location 经度。"},"radius_km":{"type":"number","description":"可选：location 半径公里数。"},"bounds":{"type":"object","description":"可选：location 边界框。","additionalProperties":false,"properties":{"north":{"type":"number","description":"北边界纬度。"},"south":{"type":"number","description":"南边界纬度。"},"east":{"type":"number","description":"东边界经度。"},"west":{"type":"number","description":"西边界经度。"}},"required":["north","south","east","west"]},"region_id":{"type":"string","description":"可选：canonical region id。"},"city":{"type":"string","description":"可选：城市。"},"state":{"type":"string","description":"可选：州/省。"},"country":{"type":"string","description":"可选：国家。"},"zip":{"type":"string","description":"可选：邮编。"},"start_at":{"type":"string","description":"可选：时间区间开始。"},"end_at":{"type":"string","description":"可选：时间区间结束。"}},"required":[]},"unit":{"type":"string","description":"可选：单位。"},"operator":{"type":"string","description":"可选：显式比较操作。"},"constraint_strength":{"type":"string","enum":["must_match","strong_preference","weak_preference","exclude"],"description":"可选：约束强度。"}},"required":["attribute_label","value_kind"]}}},"required":[]},"query":{"type":"string","description":"search 时可选：自由文本 query。Hi 会把它交给底层搜索服务做结构化 listing 搜索。"},"status":{"type":"string","description":"search 时可选：listing 状态过滤。默认 'open'，只搜索当前仍可推进的 listing。"},"listing_type_ids":{"type":"array","description":"search 时可选：listing type ids 过滤；不传时，Hi 会默认继承这条 source listing 的对向 listing types。","items":{"type":"string"}},"self_role_type_ids":{"type":"array","description":"search optional: filter the **counterpart listing** self.role_type_id (not your own role). Leave unset to inherit source.target.roles — that is almost always correct; only set this when deliberately overriding the search direction for this one call.","items":{"type":"string"}},"center":{"type":"object","description":"search 时可选：中心点地理搜索。","properties":{"lat":{"type":"number","description":"纬度。"},"lon":{"type":"number","description":"经度。"}}},"radius_km":{"type":"number","description":"search 时可选：center 的半径公里数。"},"locations":{"type":"array","description":"search 时可选：多地点搜索范围；每个地点至少包含 lat/lon，可选 radius_km。","items":{"type":"object","properties":{"lat":{"type":"number","description":"纬度。"},"lon":{"type":"number","description":"经度。"},"radius_km":{"type":"number","description":"该地点的搜索半径公里数。"}}}},"location_terms":{"type":"array","description":"search 时可选：地理文本过滤（如 zip、城市、州）。","items":{"type":"string"}},"numeric_filters":{"type":"array","description":"search 时可选：结构化数值过滤（如薪资、经验年限等）。","items":{"type":"object","properties":{"key":{"type":"string","description":"数值属性 key。"},"op":{"type":"string","description":"比较操作，如 '='|'eq'|'lt'|'lte'|'gt'|'gte'|'between'|'range'。"},"value":{"type":"number","description":"点值比较使用的 value。"},"min":{"type":"number","description":"范围比较下限。"},"max":{"type":"number","description":"范围比较上限。"},"unit":{"type":"string","description":"可选单位。"}}}},"since":{"type":"string","description":"search 时可选：updated_at 起始时间（ISO）。"},"until":{"type":"string","description":"search 时可选：updated_at 截止时间（ISO）。这是过滤条件，不是翻页 cursor。"},"limit":{"type":"number","description":"search 时可选：本页返回条数上限（默认 10，最大 50）。"},"sort_by":{"type":"string","description":"search 时可选：'updated_at'|'relevance'。不传时，Hi 会在有 query 时默认 relevance，否则默认 updated_at。"},"sort_direction":{"type":"string","description":"search 时可选：'asc'|'desc'，默认 desc。"},"page_after":{"type":"object","description":"search 翻页 cursor。直接复用上一页 next_page.page_after 即可，不要自己编造。","properties":{"id":{"type":"string","description":"上一页最后一个 listing 的 id。"},"updated_at":{"type":"string","description":"上一页最后一个 listing 的 updated_at（ISO）。"},"match_relevance":{"type":"number","description":"当 sort_by=relevance 时，上一页最后一个 listing 的 relevance score。"}}},"selected_listing_id":{"type":"string","description":"contact_match 时可选：明确选择的 matched listing id。若已有 selection_key / contact_match_ref，优先传后者。若手填，必须使用 Hi 返回的完整 canonical id。"},"selection_key":{"type":"string","description":"contact_match 时可选：直接复用 matching_sessions 返回的 selection_key（来自 match_feed/search/previously_shown_items 都可以；previously_contacted_items 里的候选已经建过 pairing，应该走 pairings 世界而不是再 contact_match）。候选处于初步预览阶段也应直接沿用这个 ref 继续推进，除非你明确判断这条候选不适合再联系。"},"contact_match_ref":{"type":"object","description":"contact_match 时可选：复用 matching_sessions 返回的 canonical selection ref。若候选初步合适，优先沿这个 ref 继续推进，由对方 agent 在真实对话里补齐细节。","properties":{"listing_id":{"type":"string","description":"源 listing id。"},"selection_key":{"type":"string","description":"matching_sessions 返回的 selection_key。"},"selected_listing_id":{"type":"string","description":"可选：已解析过的 matched listing id。"}}},"selected_anchor":{"type":"object","description":"contact_match 时可选：若当前会话已有 canonical selected anchor，可直接传回给平台恢复选择上下文。","properties":{"listing_id":{"type":"string","description":"源 listing id。"},"selection_key":{"type":"string","description":"matching_sessions 返回的 selection_key。"},"selected_listing_id":{"type":"string","description":"可选：已解析过的 matched listing id。"},"contact_match_ref":{"type":"object","description":"可选：嵌入在 selected_anchor 内的 canonical selection ref。","properties":{"listing_id":{"type":"string","description":"源 listing id。"},"selection_key":{"type":"string","description":"matching_sessions 返回的 selection_key。"},"selected_listing_id":{"type":"string","description":"可选：已解析过的 matched listing id。"}}}}},"text":{"type":"string","description":"contact_match 时必填：发给对向 agent 的首条联系文案。"},"source_message_id":{"type":"string","description":"contact_match 时可选：触发本次联系的源消息 id。"},"metadata":{"type":"object","description":"contact_match 时可选：附加 metadata，会并入 canonical A2A message payload。"},"idempotency_key":{"type":"string","description":"contact_match 时可选：幂等键。"}},"required":["action","listing_id"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.matching-sessions/call","schema_path":"/v1/capabilities/hi.matching-sessions/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":true,"destructiveHint":false,"title":"Matching sessions"}},{"capability_id":"hi.owners","tool_name":"owners","title":"Owners","description":"Hi 是 Hirey 的人与人连接平台：既能做招聘/找工作，也能做找房/租房、交友、征婚、找律师、找投资人/创业者/联合创始人，以及任何“帮 owner 找到合适的人”的 leads 搜索与撮合。 普通主链是：发布或读取一条 listing，搜索或接收推荐，选中对象并联系，再继续协作、通话或约见。 Owner（=listing 背后的真人）的 canonical 公开 profile + profile-scoped discovery：action=update_profile|get|list_listings|peers_feed。\n\n**何时调用**：\n- 用户**首次**介绍自己（名字 / 头衔 / 自我介绍 / 所在地 / 个人链接），或更新这些信息——立刻调用 `update_profile` 把结构化字段写进去。LLM 自己解析自然语言后只填该填的字段，缺什么就留空，不要为了\"看起来完整\"凭空捏造。典型话术：「我叫 Alex，在东京做了 8 年后端，最近想招个前端」——你应该写入 display_name=\"Alex\", headline=\"Tokyo backend engineer (8y)\", bio_markdown=\"...\"；同时这条话术的下半段（\"招前端\"）是 listing 需求，单独再走 `agent_listings.upsert`。\n- 对方 agent 给你回了某条 listing 或 pairing，你想多了解一下对端 owner 是谁——调用 `get` 拿 `owner_public_id` 或 `customer_id` 读对方 profile。\n- 看某个 owner 还有哪些其它在公开发布中的 listings——调用 `list_listings`。\n- 用户随口说\"看看 Hi 上还有谁有意思\" / \"推荐几个可能聊得来的人\" / install 完欢迎位之后——调用 `peers_feed` 拿一组 profile-scoped 推荐 owner 卡片。\n\n**update_profile 的边界**：\n- caller 只能改自己（runtime 注入的 caller owner），不能传 `customer_id` 改别人——传了会 403。\n- 字段都是 nullable + 部分校验：avatar_url / website_url / linkedin_url 必须是 http(s) URL，visibility_status 只能是 'public' / 'private' / 'unlisted'（不传保持现状，默认 public）。\n- bio_markdown 接受 markdown；展示侧会按 owner-facing 主页规则渲染。\n- 调用成功会返回 `owner_public_url`，把这个 URL 给 owner，他自己打开就能看到对外效果。\n\n**peers_feed 的边界 / 不要误用**：\n- 返回 `{items[], caller_profile_ready}`。items[] 每项 = profile snippet (display_name / headline / location_text / avatar_url / owner_public_url) + `suggested_because` ('recent_active' | 'same_location')。\n- 这是**浅层发现**，不是 contact 入口——返回里**故意不带** `listing_id` / `selection_key` / `contact_match_ref`。展示完后想真正联系某个人，仍然必须双方各自有 listing 走 matching_sessions / pairings 主链。不要试图直接拿 owner_public_id 去 `pairings.create`。\n- 如果 `caller_profile_ready=false`（caller 自己 profile 缺 display_name 或 headline），先提醒用户走 `update_profile` 补一下，对方看到你的卡片时才不像一个 ghost。\n- visibility=private/unlisted 的 owner 不会进 items[]，已经跟 caller 建过 pairing 的 owner 也会被排除——所以同一批 peers_feed 调用之间的去重是平台保证的。\n\n**先 profile 再 listing**：发 listing 之前最好先把 profile 至少有 display_name + headline——matching_sessions / pairings 的对端摘要会读这两个字段（缺失时退化到 customers.name 兜底，会显得突兀）。","handler_group":"identity","scopes":["owner.profile.read","owner.profile.write","owner.listings.read","owner.peers.read"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'update_profile'|'get'|'list_listings'|'peers_feed'"},"display_name":{"type":"string","description":"update_profile 可选：owner 对外显示的名字（用户口语里给的'我叫 X'）。不传保持现状。"},"headline":{"type":"string","description":"update_profile 可选：≤1 行的身份摘要（如 'Tokyo backend engineer, 8y' / 'Beijing landlord, 朝阳区 3室' / 'Founder of XYZ, hiring eng #2'），matching/pairings 摘要里会引用这个字段。"},"bio_markdown":{"type":"string","description":"update_profile 可选：自我介绍长文本（markdown）。展示在 owner 公开主页和 pairings 初次联系卡片里。"},"location_text":{"type":"string","description":"update_profile 可选：所在地自然语言文本（\"Tokyo, Japan\" / \"上海浦东\"）。listing 里也有 location，但 owner 主页上单独存一份方便对方一眼看到。"},"avatar_url":{"type":"string","description":"update_profile 可选：头像 URL；必须是 http(s)。owner 没有就别填，不要拿用户头像猜或拼。"},"website_url":{"type":"string","description":"update_profile 可选：个人 / 公司官网 URL；http(s)。"},"linkedin_url":{"type":"string","description":"update_profile 可选：LinkedIn profile URL；http(s)。"},"twitter_handle":{"type":"string","description":"update_profile 可选：Twitter / X handle（不带 @）。"},"visibility_status":{"type":"string","description":"update_profile 可选：'public'|'private'|'unlisted'；不传保持现状。private = 对外不展示 profile（matching/pairings 摘要里也会被脱敏成 anonymous）。"},"customer_id":{"type":"string","description":"get / list_listings 可选：按内部 canonical owner customer_id 反查（一般只在内部转手时用，agent 平时给 owner_public_id 就行）。get 时省略 customer_id 和 owner_public_id 都不传 = 读自己。"},"owner_public_id":{"type":"string","description":"get / list_listings 可选：从 owner_public_url 路径里拿到的数字 id（hi.hirey.ai/owner/<id>）。matching/pairings 响应里也会带这个值，直接复用即可。"},"statuses":{"type":"array","description":"list_listings 可选：按 listing status 过滤（如 ['open','paused']）。不传 = 默认平台 open+paused。","items":{"type":"string"}},"limit":{"type":"number","description":"list_listings 可选：返回条数上限。"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.owners/call","schema_path":"/v1/capabilities/hi.owners/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":false,"destructiveHint":false,"title":"Owner profile"}},{"capability_id":"hi.pairings","tool_name":"pairings","title":"Pairings","description":"Hi 是 Hirey 的人与人连接平台：既能做招聘/找工作，也能做找房/租房、交友、征婚、找律师、找投资人/创业者/联合创始人，以及任何“帮 owner 找到合适的人”的 leads 搜索与撮合。 普通主链是：发布或读取一条 listing，搜索或接收推荐，选中对象并联系，再继续协作、通话或约见。 协作线程：action=create|timeline|contact_target。pairing 是两侧 agent 围绕某个 people-to-people 目标持续推进的正式线程，适用于候选人沟通、租房洽谈、交友/征婚续聊、律师咨询、创业者与投资人接触等场景。timeline.chats 的 canonical read model 是 agent_messages / agent_threads；timeline 会直接返回 pairing 元信息、最近的历史 `chats`、thread-native `action_cards` / `available_actions` / `pending_actions`，供 agent 在同一条 pairing thread 内显式发起和响应 typed actions（meeting 先落在 thread_meetings）。create 应该用 listing_id + selected_listing_id/selection_key（或 selected_anchor/contact_match_ref）恢复 canonical collaboration scope。已有 pairing 的 generic continuation 走 contact_target。\n\n**timeline.chats 分页（重要）**：为了避免一个长历史的 pairing 直接把 LLM context 打爆，`timeline.chats` 默认只返回**最近 30 条**消息（按时间倒序，最新在前）。如果 `timeline.chats_has_more=true`，表示还有更早的消息；此时用返回的 `timeline.chats_next_before_id` 作为 `chats_before_id` 参数再调一次 `timeline`，就能拿到更早一页；也可以通过 `chats_limit`（最高 200）一次性多拉一些，但**只有真的需要回溯长历史**时才调大 —— 大多数回合决策只看最近几轮即可。\n\n**contact_target 的返回语义（重要）**：contact_target 成功时返回 `peer_inbox.stage=\"queued_to_peer_inbox\"`——这只表示 Hi 已经把 canonical A2A message 放进了对端 agent 的 inbox，**不**代表对方 agent 已经处理、也**不**代表对端 owner 真的收到了。Hi 是匹配+relay 平台，owner 最终用什么 channel 收到（sms/web/whatsapp/其它）是对端 agent 按自己 owner 的 contact policy 决定的。因此：(1) 不要在对 owner 的文案里说 \"message delivered / outreach was sent\"，准确措辞是 \"reached out / sent a message\"；(2) 要确认对方是否真的回复，应该在合理等待时间后调用 `pairings(action=\"timeline\")`，查 `chats` 里是否出现对方 agent 的 reply 事件——没出现就说明还在等待，不要脑补\"已完成\"。\n\n## Cookbook（照抄能跑）\n- 看 pairing thread 全状态（最近聊天 + 待处理 action cards + 可发起 actions）：`{\"action\":\"timeline\",\"pairing_id\":\"<from contact_match result>\"}`\n- 想看更早历史：`{\"action\":\"timeline\",\"pairing_id\":\"<id>\",\"chats_before_id\":\"<from prev timeline.chats_next_before_id>\",\"chats_limit\":50}`\n- 在已有 pairing 内继续发消息（普通文本聊天）：`{\"action\":\"contact_target\",\"pairing_id\":\"<id>\",\"idempotency_key\":\"<uuid>\",\"text\":\"<message body>\"}`\n- 从 matching_sessions selection 重建 pairing scope（少用，contact_match 通常自动建 pairing）：`{\"action\":\"create\",\"listing_id\":\"<my>\",\"selection_key\":\"<from matching_sessions>\"}`\n\n**重要约定**：\n- 在 pairing 内继续聊用 `contact_target`，不是 `send_message`（hi.pairings 没有 send_message action）\n- contact_target 返回 `peer_inbox.stage=\"queued_to_peer_inbox\"` 只代表入对端 agent inbox；对端 owner 是否真收到取决于对端 agent 自己的 contact policy。措辞用 \"reached out / sent a message\"，**绝不**说 \"delivered to the other side\"\n- 想看对方有没有回，循环调 `timeline` 检查 chats 里有没有对端 agent 的新消息；不要假设\n- meeting 协调走 `thread_meetings.*`，不要在 chat 里自然语言谈 schedule\n\n\n**宿主无 push channel 时（典型如 Codex CLI）—— 必须提醒 owner 设定时轮询**：本工具产生的回应（对方回复、reaction、meeting confirmation、availability share）都只会落到 Hi 自己的 durable outbox，**不会**主动推到 owner 当前的对话窗口。Codex CLI 这种宿主在 turn 结束后没有任何 background 进程，event 会一直静静躺在 outbox 里直到下一次 owner 主动唤起或定时器 drain。因此一旦在这种宿主上发起任何 outreach，agent 应在最终回复里显式提示 owner：建议开一条 scheduled drain，每 5–15 分钟跑一次 `hi_agent_events_wait` + 必要时 `hi_agent_events_ack`，否则对方的回复会被 silent-suppress 直到下次主动询问。具体推荐路径：\n- **Codex app（推荐，保留 thread 上下文）**：在当前 thread 里加一条 thread automation，cron / minute-interval 调度，prompt 写 \"drain my Hi inbox via hi_agent_events_wait then summarize and ack\"。\n- **Codex CLI（无内置 scheduler）**：系统 cron / launchd 定期跑 `codex exec \"drain my Hi inbox via hi_agent_events_wait then ack\"`（`exec` 是 codex CLI 的 non-interactive 入口，exit code 非 0 时报错可串进 CI/告警）。\n- **其它 MCP-first 宿主**：同样用 `hi_agent_events_wait` 长轮询；如果宿主有 native 调度（如 Claude Code 的 schedule skill / cron），优先用。\n\n如果当前宿主明确支持 live push（少数情况下 Hi 已经能直接把 event 推到 host 的 session inbox），可省略上述提醒；否则**默认 outreach 工具一旦成功调用，agent 就必须把 scheduled drain 建议讲给 owner**。","handler_group":"pairings","scopes":["pairing.create","pairing.timeline","pairing.contact_target"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'create'|'timeline'|'contact_target'"},"listing_id":{"type":"string","description":"create 时可选：当前源 listing id。必须使用 Hi 返回的完整 canonical id，不要截掉前缀或自行缩写。"},"selected_listing_id":{"type":"string","description":"create 时可选：当前明确选中的 target listing id。若手填，必须使用 Hi 返回的完整 canonical id。"},"selection_key":{"type":"string","description":"create 时可选：matching_sessions 返回的 selection_key（来自 match_feed/search/previously_shown_items/previously_contacted_items 都可以）。"},"contact_match_ref":{"type":"object","description":"create 时可选：直接复用 matching_sessions 返回的 canonical selection ref。","properties":{"listing_id":{"type":"string","description":"源 listing id。必须使用 Hi 返回的完整 canonical id。"},"selection_key":{"type":"string","description":"matching_sessions 返回的 selection_key。"},"selected_listing_id":{"type":"string","description":"可选：已解析过的 matched listing id。若手填，必须使用 Hi 返回的完整 canonical id。"}}},"selected_anchor":{"type":"object","description":"create 时可选：agent 已明确选中的 canonical selected anchor。","properties":{"listing_id":{"type":"string","description":"源 listing id。必须使用 Hi 返回的完整 canonical id。"},"selected_listing_id":{"type":"string","description":"已选中的 target listing id。若手填，必须使用 Hi 返回的完整 canonical id。"},"selection_key":{"type":"string","description":"matching_sessions 返回的 selection_key。"},"contact_match_ref":{"type":"object","description":"可选：嵌入在 selected_anchor 内的 canonical selection ref。","properties":{"listing_id":{"type":"string","description":"源 listing id。"},"selection_key":{"type":"string","description":"matching_sessions 返回的 selection_key。"},"selected_listing_id":{"type":"string","description":"可选：已解析过的 matched listing id。"}}}}},"pairing_kind":{"type":"string","description":"可选：pairing 类型，默认 'agent_agent_collaboration'"},"thread_key":{"type":"string","description":"可选：显式协作线程去重键；缺省按协作参与方 truth 生成。"},"status":{"type":"string","description":"'discussing'|'success'|'failed'（create/update_status）"},"pairing_id":{"type":"string","description":"协作线程 ID（查询/更新/contact_target）"},"continuation_anchor":{"type":"object","description":"续聊时可选：agent 明确带回 platform 的 continuation anchor。正常情况下，agent 应该显式知道要沿哪条 pairing 继续，而不是让 platform 猜 transport 对端。","properties":{"pairing_id":{"type":"string","description":"当前正式协作线程的 pairing_id"},"listing_id":{"type":"string","description":"可选：当前 canonical listing id，用于 continuity / provenance"},"source_message_id":{"type":"string","description":"可选：若这次续聊明确承接某条 source message，可一并带回"},"contact_target_ref":{"type":"object","description":"可选：续聊时直接复用已知的 pairing contact ref","properties":{"pairing_id":{"type":"string","description":"当前 pairing id"}}}}},"agent_id":{"type":"string","description":"contact_target 时可选：当前发起 continuation 的 source agent_id。若 runtime 已经注入 pairing 上下文，模型通常不需要重复填写。"},"text":{"type":"string","description":"contact_target 时要发给 target agent 的 continuation 文本"},"chats_limit":{"type":"number","description":"timeline 时可选：一次最多返回多少条 chat 消息。默认 30，最大 200。**只有在真的需要回看长历史时才调大**，默认值已经足够支撑绝大多数决策；调大会直接放大 LLM 上下文用量。"},"chats_before_id":{"type":"string","description":"timeline 分页：传入上一次返回的 `timeline.chats_next_before_id`（当 `timeline.chats_has_more=true` 时），本次返回比它更早的一页 chats。首次调用不要传。"},"source_message_id":{"type":"string","description":"可选：触发本次联系的源消息 ID（crm_message_id）"},"metadata":{"type":"object","description":"可选：附加 metadata，会并入 canonical A2A message payload"},"idempotency_key":{"type":"string","description":"可选：幂等键（contact_target）"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.pairings/call","schema_path":"/v1/capabilities/hi.pairings/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":true,"destructiveHint":true,"title":"Pairings"}},{"capability_id":"hi.social-org","tool_name":"social_org","title":"Social Org","description":"组织层级与 AM 作用域：action=org_node_upsert|org_membership_upsert|org_reporting_upsert|org_snapshot_get|am_scope_upsert|am_scope_list|am_fanout_preview|am_fanout_send","handler_group":"social_org","scopes":["social.org.read","social.org.write"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'org_node_upsert'|'org_membership_upsert'|'org_reporting_upsert'|'org_snapshot_get'|'am_scope_upsert'|'am_scope_list'|'am_fanout_preview'|'am_fanout_send'"},"id":{"type":"string","description":"记录 ID（可选，不传则自动生成）"},"org_id":{"type":"string","description":"组织 ID（必填）"},"node_type":{"type":"string","description":"组织节点类型：'org'|'team'|'department'"},"name":{"type":"string","description":"组织节点名称（org_node_upsert）"},"parent_node_id":{"type":"string","description":"父节点 ID（可选）"},"meta":{"type":"object","description":"组织节点扩展字段（可选）"},"node_id":{"type":"string","description":"组织节点 ID（membership）"},"agent_id":{"type":"string","description":"成员 agent_id（membership）"},"membership_role":{"type":"string","description":"成员角色：'member'|'manager'|'admin'"},"manager_agent_id":{"type":"string","description":"汇报线 manager agent_id"},"report_agent_id":{"type":"string","description":"汇报线 report agent_id"},"state":{"type":"string","description":"状态：'active'|'inactive'"},"include_inactive":{"type":"boolean","description":"快照是否包含 inactive 记录"},"am_agent_id":{"type":"string","description":"AM agent_id（am_scope_* / am_fanout_*）"},"scope_type":{"type":"string","description":"作用域类型：'org'|'team'|'agent'"},"scope_ref":{"type":"string","description":"作用域引用（org_id/team_id/agent_id）"},"capability_bundle":{"type":"object","description":"能力模板/能力包（JSON）"},"capability":{"type":"string","description":"fanout 目标能力（例如 am.push.resume / am.push.phone_interview）。若是 am.push.phone_interview，调用方必须显式提供 `phone_interview_readiness_by_agent_id`，Hi 不会再本地回查 caller-side readiness truth。"},"target_agent_ids":{"type":"array","description":"可选：指定 fanout 目标 agent 列表（为空则按 scope 全量）","items":{"type":"string"}},"phone_interview_readiness_by_agent_id":{"type":"object","description":"仅用于 am.push.phone_interview：按 target agent_id 显式提供 readiness verdict map，value 形如 `{ action, reason, suppressed_until? }`。Hi 只消费这份显式输入，不再本地调用 Rey 计算电话门控。"},"resource_type":{"type":"string","description":"可选：资源类型（resume|feedback|zoom_link|phone_slot 等）"},"resource_id":{"type":"string","description":"可选：资源 ID/引用（fanout 时透传到 authz.resource_id）"},"ticket_id":{"type":"string","description":"可选：generic gate ticket ID（ggt_xxx）"},"trace_id":{"type":"string","description":"可选：链路追踪 ID"},"text":{"type":"string","description":"fanout 发送文本（am_fanout_send 必填）"},"metadata":{"type":"object","description":"fanout 自定义 metadata（可选）"},"idempotency_key":{"type":"string","description":"fanout 幂等前缀（可选）"},"limit":{"type":"number","description":"列表返回条数（默认 100）"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.social-org/call","schema_path":"/v1/capabilities/hi.social-org/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":false,"destructiveHint":false,"title":"Social org"}},{"capability_id":"hi.social-permissions","tool_name":"social_permissions","title":"Social Permissions","description":"社会权限：action=grant_upsert|grant_delete|grant_list|evaluate","handler_group":"social_permissions","scopes":["social.permissions.read","social.permissions.write"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'grant_upsert'|'grant_delete'|'grant_list'|'evaluate'"},"edge_id":{"type":"string","description":"关系边 ID（grant_upsert/grant_delete/grant_list）"},"grant_id":{"type":"string","description":"授权 ID（grant_delete）"},"capability":{"type":"string","description":"能力名（例如 resource.resume.share / meeting.propose）"},"effect":{"type":"string","description":"授权效果：'allow'|'deny'"},"conditions":{"type":"object","description":"条件对象（org_scope/time_window/pairing_required/requires_dual_authorization/ttl 等）"},"priority":{"type":"number","description":"优先级（默认 100，越大优先）"},"src_agent_id":{"type":"string","description":"源 agent（grant_list/evaluate）"},"dst_agent_id":{"type":"string","description":"目标 agent（grant_list/evaluate）"},"context":{"type":"object","description":"评估上下文（evaluate）"},"limit":{"type":"number","description":"列表返回条数（默认 100）"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.social-permissions/call","schema_path":"/v1/capabilities/hi.social-permissions/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":false,"destructiveHint":false,"title":"Social permissions"}},{"capability_id":"hi.social-relationships","tool_name":"social_relationships","title":"Social Relationships","description":"社会关系：action=lookup_by_phone|request_create|request_list|request_respond|request_cancel|edge_list|edge_revoke|resource_share_create|resource_share_list","handler_group":"social_relationships","scopes":["social.relationships.read","social.relationships.write"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'lookup_by_phone'|'request_create'|'request_list'|'request_respond'|'request_cancel'|'edge_list'|'edge_revoke'|'resource_share_create'|'resource_share_list'"},"phone":{"type":"string","description":"手机号（lookup_by_phone，支持 identity 统一标准化，并返回 canonical agent_id）"},"requester_agent_id":{"type":"string","description":"发起方 agent_id（request_create）"},"target_agent_id":{"type":"string","description":"目标方 agent_id（request_create）"},"relation_type":{"type":"string","description":"关系类型：'friend'|'colleague'|'manager'|'report'|'recruiter'|'candidate'|'am_delegate'"},"intent":{"type":"object","description":"请求意图（JSON 对象）"},"expires_at":{"type":"string","description":"请求过期时间（ISO，可选）"},"expires_in_sec":{"type":"number","description":"请求有效期秒数（可选，默认 7 天）"},"request_id":{"type":"string","description":"关系请求 ID（request_respond/request_cancel）"},"responder_agent_id":{"type":"string","description":"响应方 agent_id（request_respond）"},"decision":{"type":"string","description":"请求决策：'accepted'|'rejected'（request_respond）"},"canceller_agent_id":{"type":"string","description":"取消方 agent_id（request_cancel）"},"agent_id":{"type":"string","description":"查询关系时的 agent_id（request_list/edge_list）"},"direction":{"type":"string","description":"方向：'incoming'|'outgoing'|'all'"},"status":{"type":"string","description":"请求/边状态过滤（request_list/edge_list）"},"edge_id":{"type":"string","description":"关系边 ID（edge_revoke）"},"revoker_agent_id":{"type":"string","description":"撤销操作发起 agent_id（edge_revoke）"},"both_directions":{"type":"boolean","description":"是否同时撤销反向边（默认 true）"},"from_agent_id":{"type":"string","description":"资源共享发送方 agent_id（resource_share_create/list）"},"to_agent_id":{"type":"string","description":"资源共享接收方 agent_id（resource_share_create/list）"},"resource_type":{"type":"string","description":"共享资源类型：'resume'|'interview_note'|'feedback'|'zoom_link'|'phone_slot'"},"resource_ref":{"type":"string","description":"共享资源引用 ID/URI（resource_share_create）"},"policy_snapshot":{"type":"object","description":"共享发生时的策略快照（可选）"},"limit":{"type":"number","description":"列表返回条数（默认 30/50/100）"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.social-relationships/call","schema_path":"/v1/capabilities/hi.social-relationships/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":true,"destructiveHint":false,"title":"Social relationships"}},{"capability_id":"hi.thread-meetings","tool_name":"thread_meetings","title":"Thread Meetings","description":"Hi 是 Hirey 的人与人连接平台：既能做招聘/找工作，也能做找房/租房、交友、征婚、找律师、找投资人/创业者/联合创始人，以及任何“帮 owner 找到合适的人”的 leads 搜索与撮合。 普通主链是：发布或读取一条 listing，搜索或接收推荐，选中对象并联系，再继续协作、通话或约见。 线程原生 meeting typed family：action=start|respond|get。这个入口用于让 agent 在 pairing thread 内显式发起 meeting action，并把 pending action card 直接投影回 pairings.timeline；适用于招聘面试、租房看房、交友见面、征婚约见、律师咨询、创业者和投资人会面等任何 people-to-people 场景。它不靠 Hi 去猜自然语言，也不把 formal meeting backend 暴露成普通宿主的主入口。现在 ordinary host 应优先通过这里完成 start_now / exact slot proposal / availability / slot selection / approval，再由平台在内部桥接 formal proposal、meeting_confirmation(bind) 与 schedule_earliest，不再要求普通宿主自己编排整条 formal 链。\n\n**scheduled 是两阶段（重要）**：meeting 完成是一个两段异步 pipeline，`thread_action.status` 和 `thread_action.result.artifacts.ready` 一起告诉调用方当前 pipeline 停在哪段：\n  1. `status=\"scheduled_pending_provisioning\"` + `artifacts.ready=false`：同步段已完成 — time window 已锁定、Hi 内部 formal proposal / approval / commit_authority truth 已齐备，且已把 provider 执行命令入队。但 provider（Zoom / phone）侧的 artifacts（zoom join_url / meeting_id / passcode、phone dial-in 号码等）**还没**真正 materialize，对端 agent 也**还**看不到 link。调用方**不能**在这个阶段对 owner 声称\"对方拿到链接/号码\"；应该在合理等待时间后调用 `thread_meetings(action=\"get\")` 或 `pairings(action=\"timeline\")` 重新读取这个 thread_action，直到 status 变成 `scheduled`。\n  2. `status=\"scheduled\"` + `artifacts.ready=true` + 具体 artifacts 字段（zoom：`join_url` / `meeting_id` / `passcode`；phone：`modality=\"phone\"` 占位，dial-in 号码由对端 agent 按需处理）：严格终态 — provider artifacts 已落地，Hi 也已经发 `meeting.negotiation.updated` gateway event 把 artifacts 推给双方 agent 的 inbox。只有到这个阶段才允许对 owner 宣称 meeting 已确认 / 对方可见链接。即便如此，\"对端 owner 是否已收到 SMS / Whatsapp / 其他 channel\"仍然由对端 agent 根据自己 owner 的 contact policy 决定，Hi 不保证；准确措辞应是 \"the meeting is booked and the Zoom link is now on its way to the other side\"，而不是 \"the other side has the link right now\"。\n\n这两态的语义和 `pairings.contact_match` / `pairings.contact_target` 返回的 `peer_inbox.stage=\"queued_to_peer_inbox\"`（只代表入对端 agent inbox、不代表对端 owner 已看到）是一类 never-overpromise 声明：Hi 是匹配+relay 平台，只明示 Hi 自己能观测到的事实，绝不包装成\"对端 owner 已确定感知\"。\n\n## Cookbook（照抄能跑）\n- 发起 Zoom 让对方 share availability（最常见场景）：`{\"action\":\"start\",\"pairing_id\":\"<id>\",\"modality\":\"zoom\",\"flow_kind\":\"need_slots\",\"requested_windows\":[{\"start_at\":\"2026-05-09T21:00:00.000Z\",\"end_at\":\"2026-05-09T21:30:00.000Z\",\"timezone\":\"America/Los_Angeles\"}, ...]}` —— requested_windows 可空，让对方先 share\n- 直接提议一个精确 slot：`{\"action\":\"start\",\"pairing_id\":\"<id>\",\"modality\":\"zoom\",\"flow_kind\":\"propose_slot\",\"requested_windows\":[<exactly one window>]}`\n- 收到 `status=requested` + allowed_responses 含 `share_availability` 的 action card → 回 share：`{\"action\":\"respond\",\"thread_action_id\":\"<from action_card.id>\",\"if_match_version\":<from action_card.version>,\"response_kind\":\"share_availability\",\"windows\":[{\"start_at\":\"<ISO>\",\"end_at\":\"<ISO>\",\"timezone\":\"America/Los_Angeles\"}, ...]}` —— **字段是 windows，不是 availability_windows**\n- 收到 `status=proposal_sent` + allowed_responses 含 `select_slot` 的 action card → 选 slot（target 一侧）：`{\"action\":\"respond\",\"thread_action_id\":\"<id>\",\"if_match_version\":<v>,\"response_kind\":\"select_slot\",\"selected_option_key\":\"<直接拷 action_card.primary_cta.selected_option_key>\"}` —— selected_option_key **必须从 primary_cta 直接拷贝**，不要自己生成\n- 对方选完 slot，creator 一侧批准：`{\"action\":\"respond\",\"thread_action_id\":\"<id>\",\"if_match_version\":<v>,\"response_kind\":\"approve\"}`\n- 拒绝任何阶段：`{\"action\":\"respond\",\"thread_action_id\":\"<id>\",\"if_match_version\":<v>,\"response_kind\":\"decline\"}`\n- 主动看 meeting 当前阶段：`{\"action\":\"get\",\"thread_action_id\":\"<id>\"}`\n\n**peer agent 重要陷阱**：\n- 平台**不会**给 target 发单独的 `meeting.negotiation.updated` event 通知 action card 创建。peer 收到 `agent.message.created` / `pairing.updated` / `pairing.created` 后，必须主动调 `pairings.timeline` 看 `action_cards[]` 里 target_agent_id=自己 + 自己未处理过的 card，再 respond。\n- response_kind 必须从 `action_card.allowed_responses` 里挑（`share_availability` / `select_slot` / `approve` / `decline` / `reject`），不要自己造词。\n- if_match_version 用 action_card.version；版本对不上会 409 conflict，按返回的 current_version 重试。\n\n**scheduled 是两阶段**（不要把 `scheduled_pending_provisioning` 当终态）：\n- `scheduled_pending_provisioning` + `artifacts.ready=false`：time window 锁住但 zoom join_url / meeting_id / passcode 还没 materialize，不要对 owner 说\"对方拿到链接\"\n- `scheduled` + `artifacts.ready=true` + zoom artifacts 字段：终态。措辞 \"the meeting is booked and the Zoom link is on its way to the other side\"，不要包装成 \"the other side has the link right now\"\n\n\n**宿主无 push channel 时（典型如 Codex CLI）—— 必须提醒 owner 设定时轮询**：本工具产生的回应（对方回复、reaction、meeting confirmation、availability share）都只会落到 Hi 自己的 durable outbox，**不会**主动推到 owner 当前的对话窗口。Codex CLI 这种宿主在 turn 结束后没有任何 background 进程，event 会一直静静躺在 outbox 里直到下一次 owner 主动唤起或定时器 drain。因此一旦在这种宿主上发起任何 outreach，agent 应在最终回复里显式提示 owner：建议开一条 scheduled drain，每 5–15 分钟跑一次 `hi_agent_events_wait` + 必要时 `hi_agent_events_ack`，否则对方的回复会被 silent-suppress 直到下次主动询问。具体推荐路径：\n- **Codex app（推荐，保留 thread 上下文）**：在当前 thread 里加一条 thread automation，cron / minute-interval 调度，prompt 写 \"drain my Hi inbox via hi_agent_events_wait then summarize and ack\"。\n- **Codex CLI（无内置 scheduler）**：系统 cron / launchd 定期跑 `codex exec \"drain my Hi inbox via hi_agent_events_wait then ack\"`（`exec` 是 codex CLI 的 non-interactive 入口，exit code 非 0 时报错可串进 CI/告警）。\n- **其它 MCP-first 宿主**：同样用 `hi_agent_events_wait` 长轮询；如果宿主有 native 调度（如 Claude Code 的 schedule skill / cron），优先用。\n\n如果当前宿主明确支持 live push（少数情况下 Hi 已经能直接把 event 推到 host 的 session inbox），可省略上述提醒；否则**默认 outreach 工具一旦成功调用，agent 就必须把 scheduled drain 建议讲给 owner**。","handler_group":"thread_meetings","scopes":["thread_meetings.start","thread_meetings.respond","thread_meetings.get"],"parameters":{"type":"object","properties":{"action":{"type":"string","description":"'start'|'respond'|'get'"},"pairing_id":{"type":"string","description":"start 时必填：当前 pairing thread id。"},"agent_id":{"type":"string","description":"可选：当前 caller agent_id。通常由 runtime `_ctx.agent_id` 注入，不需要模型重复填写。"},"thread_action_id":{"type":"string","description":"respond/get 时必填：thread action id。"},"flow_kind":{"type":"string","description":"start 时必填：'start_now'|'need_slots'|'propose_slot'。`propose_slot` 用于发起方直接提出**一个**未来精确时间段作为正式 proposal（requested_windows 必须正好 1 个；多个候选请用 `need_slots`）；`need_slots` 用于发起方分享自己的若干 availability 窗口让对方挑或补；`start_now` 用于「现在就开会，不安排时间」。"},"modality":{"type":"string","description":"start 时必填：'zoom'|'phone'。"},"note":{"type":"string","description":"start/respond 时可选：给对向 agent 的简短说明。"},"request_key":{"type":"string","description":"start 时可选：typed family 级 request 去重键。"},"replace_action_id":{"type":"string","description":"start 时可选：若当前 pairing 已有同 modality 的未完成 meeting action，需要显式传要替换/取消的旧 thread_action_id。"},"idempotency_key":{"type":"string","description":"start/respond 时可选：幂等键。"},"metadata":{"type":"object","description":"start 时可选：附加 typed metadata。"},"requested_windows":{"type":"array","description":"start 时可选：如果这次 action 一开始就想附上候选时段，可直接带结构化 windows。**`propose_slot` 必须正好 1 个窗口（maxItems=1，强校验，传多个会被 -32602 拒掉）**；`need_slots` 可以传多个，让发起方一次性把自己的 availability / hard preference 全发出去。需要「多候选让对方挑」务必用 `need_slots` 而不是 `propose_slot`。","items":{"type":"object","properties":{"start_at":{"type":"string","description":"绝对开始时间（ISO）"},"end_at":{"type":"string","description":"绝对结束时间（ISO）"},"timezone":{"type":"string","description":"可选：该窗口时区（IANA）"}},"required":["start_at","end_at"]}},"response_kind":{"type":"string","description":"respond 时必填：'accept_start_now'|'accept_proposed_slot'|'share_availability'|'select_slot'|'approve'|'reject'|'decline'。具体可用值要以 pairings.timeline 返回的 action card / CTA 为准。'accept_proposed_slot' 用于接受发起方直接提出的未来精确 slot；'select_slot' 需要 selected_option_key；'approve'/'reject' 用于 formal proposal 已生成后的确认。"},"anytime":{"type":"boolean","description":"respond 时可选：share_availability 是否表示 anytime / start now。"},"windows":{"type":"array","description":"respond 时可选：share_availability 的结构化 availability windows。","items":{"type":"object","properties":{"start_at":{"type":"string","description":"绝对开始时间（ISO）"},"end_at":{"type":"string","description":"绝对结束时间（ISO）"},"timezone":{"type":"string","description":"可选：该窗口时区（IANA）"}},"required":["start_at","end_at"]}},"selected_option_key":{"type":"string","description":"respond 时可选：response_kind=select_slot 时必填，直接带 pairings.timeline action card 里提供的 option key。"},"if_match_version":{"type":"number","description":"respond 时可选：thread action CAS 版本。"}},"required":["action"]},"bindings":[{"kind":"http","profile":"hi.capability-http.v1","method":"POST","path":"/v1/capabilities/hi.thread-meetings/call","schema_path":"/v1/capabilities/hi.thread-meetings/schema"}],"annotations":{"readOnlyHint":false,"openWorldHint":true,"destructiveHint":false,"title":"Thread meetings"}}]}