| 字段 | 值 |
|---|---|
| 版本 | v1.0 |
| 最后更新日期 | 2026-10-14 |
| 状态 | 生效(编码基线);标注 ❓ 者为推断,需服务端核对 |
| 本次变更原因 | 初次创建。补齐 CLAUDE.md「待确认项」指出的缺口:云函数契约此前散见于存量 README 与调用点,无集中文档 |
| 事实来源 | 存量项目 E:\work\fmode-app 调用点逆向(子代理只读盘点)+ 存量 docs/03-interface/hermes-agent-data-sources.md |
| 核对状态 | 请求参数与返回字段名 已由 TS interface + 调用处校验双重确认(标 ✅);仅少数语义为推断(标 ❓) |
前端消费方式:一律经
core/api/抽象层;业务组件禁止直接调用FmodeApi或其实现。 抽象层定义见《数据访问层设计.md》。
POST https://server.fmode.cn/api/functions
Headers:
Content-Type: application/json
X-Parse-Application-Id: ncloudmaster
X-Parse-Session-Token: <sessionToken> # 有则带
Body:
{ "id": "<云函数 objectId>", "token": "<sessionToken>", "params": { ... } }
错误处理:HTTP 200 但 body.code 为 401 / 403 时视为业务错误,须抛出。
错误文案取值顺序:msg → mess → message。
| 常量 | 值 |
|---|---|
PARSE_BASE |
https://server.fmode.cn/parse |
FUNCTION_API |
https://server.fmode.cn/api/functions |
PARSE_APP_ID |
ncloudmaster |
LOGIN_COMPANY |
E4KpGvTEto |
| OBS 公网前缀 | https://s3.fmode.cn/<key> |
| Matrix homeserver | https://matrix.fmode.cn,serverName fmode.cn |
xlosi3m46q — 数字生命状态(AgentStatus)✅调用方:实况服务(唯一轮询器)
| 操作 | params |
返回 |
|---|---|---|
| 列表查询 | { op: 'query', scope: 'all' \| 'company' \| 'mine' } |
{ code: 200, agents: AgentStatusItem[] } |
| 单条查询 | { op: 'query', scope, agentId } |
{ code: 200, agent: AgentStatusItem };code 404/403 → 返回 null |
| 写入性别 | { agentId, field: 'gender', value: 'male' \| 'female' } |
{ code: 200 } |
⚠️
scope降级链:存量按all → company → mine逐级降级取数。 v2 处置:降级链保留在服务端,前端只按自身 ACL 期望值请求一次;失败即真实失败(不静默降级), 避免「权限不足被伪装成空列表」(FR-20 AC-20.3)。
AgentStatusItem(✅ 除标注外)| 字段 | 类型 | 说明 |
|---|---|---|
objectId / agentId |
string | 实体 id |
name |
string | 数字生命名称 |
botName / botAvatar |
string | 展示名 / 头像 |
gender ❓ |
'male' \| 'female' \| 'unknown' |
取值域推断 |
status |
'running' \| 'idle' \| 'error' \| 'offline' \| 'stopped' |
✅ 枚举确定 |
currentTask |
string | 当前任务(单值) |
currentAction |
string | 当前动作描述 |
progress ❓ |
number | 语义推断:整数=百分比,0<x<1=小数比例 |
heartbeatAt / updatedAt |
string(ISO) | 心跳 / 更新时间 |
host |
string(JSON) | 见下方结构 |
channels |
string(JSON) | 见下方结构 |
balance |
string(JSON) | 见下方结构 |
usage / usageSessions |
string(JSON) ❓ | token 用量 |
user |
Pointer(_User) |
归属用户(含 nickname/username/mobile/avatar) |
company |
Pointer(Company) |
租户 |
🔴 注意:
host/channels/balance/usage均为字符串形态的 JSON, 需兼容「已是对象」与「是字符串」两种形态后解析(存量parseJsonLoose的教训)。
// host(JSON 字符串)
{ cpuPercent?: number; memPercent?: number; diskPercent?: number }
// channels(JSON 字符串)
{ wecom?: boolean; wecomBotId?: string;
matrix?: boolean; homeserver?: string;
matrixConfig?: { userId?: string; homeserver?: string; serverName?: string };
wecomConfig?: { botId?: string; corpName?: string } }
// balance(JSON 字符串;兼容旧键 remainRmb)
{ remainCny?: number; remainRmb?: number; pageUrl?: string }
🔴 死字段(禁止消费):
tasks[]/runningTasks[]/currentTasks[]—— 上报链路从未实现,永远为空。v2 任务数据改由AgentTask域承载(FR-07b)。
lfYlgU7SkK — 交付成果 ✅| 操作 | params |
返回 |
|---|---|---|
| 列表 | { action: 'list', agentId?, limit? } |
{ code, count, deliverables: DeliverableItem[] } |
| 按项目分组 | { action: 'byProject', limit? } |
{ code, groups: DeliverableGroup[] } |
| 上报(写) | { action: 'report', ... } |
服务端存在,v2 不调用 |
各调用点的 limit 基线(✅ 确定):成果页 200 / 项目页 200 / 事件派生 200 / 任务附件 12 / 详情状态面板 30
interface DeliverableItem {
id?: string; objectId?: string;
agentId: string;
title: string;
summary?: string;
project?: string; projectName?: string;
artifacts: { name: string; url: string; type: string }[];
tags?: string[];
deliveredAt: string;
status?: string; // ❓ 取值:`delivered`=完成;含 `fail`/`error` 子串=失败
extra?: unknown;
}
interface DeliverableGroup {
project?: string; projectName: string; count: number; items: DeliverableItem[];
}
RP5Ht55NeX — Matrix 身份开通(provision)✅| 操作 | params |
返回 |
|---|---|---|
| 开通 | { agentId } 或 {} |
MatrixProvisionResult |
| 校验/刷新 | { agentId?, validate: 1 } |
同上 |
interface MatrixProvisionResult {
code: number;
cached?: boolean; // v3 P1:绑定表命中 = 幂等秒进
bindingId?: string;
status?: string;
userMxId: string | null;
agentMxId: string | null;
homeserver: string;
accessToken: string;
deviceId: string;
roomId: string | null;
userCreated?: boolean;
}
校验规则:必须 code === 200 && accessToken && userMxId,否则抛错。
消费流程:本地绑定缓存优先 → 静默 whoami 探活 → 失效才 validate(避免每次进会话都开通)。
zl4yU8PAEB — Token 同步 ✅(承载 FR-02 AC-02.4)| 操作 | params |
返回 |
|---|---|---|
| 回写 | { agentId, token } |
{ code, mess? } |
用途:登录后把 SessionToken 回写到数字生命容器(?reauth=1&agentId= 自愈流程);失败不阻塞跳转。
🔴 改造要求(FR-02 AC-02.4 / NFR-04):该函数应同时作为 租户归属的权威判定方。 v2 处置:前端只读服务端返回的
company,禁止PUT /users/<id>自改(存量反模式)。 未就绪前的降级:前端按服务端返回的company使用;若服务端仍返回旧值,前端不做纠正。
AlP56LCKFm — 上传预签名 ✅| 操作 | params |
返回 |
|---|---|---|
| 取签名 | { filename, mimeType, size } |
{ code, uploadUrl, key, publicUrl, headers? } |
上传链路(✅ 确定):
选文件
→ uploadUrl(filename, mimeType, size) [云函数 AlP56LCKFm]
→ fetch(uploadUrl, { method:'PUT', headers, body:file }) [OBS 直传,前端不经手密钥]
→ 得 { key, publicUrl }
→ Matrix 发文件卡:m.text,body = JSON.stringify({ kind:'file', name, size, mimeType, url })
默认 headers 兜底:{ 'Content-Type': mimeType, 'x-obs-acl': 'public-read' }
缺 uploadUrl 即抛错(不得静默降级为本地 blob)。
| 项 | 状态 |
|---|---|
| 数据源 | 容器 /opt/data/kanban.db(SQLite 只读)→ 采集脚本 kanban-report.py → 云函数 → Parse |
| 表 | AgentTask / AgentTaskRun / AgentLiveEvent 已建;AgentTaskComment / AgentTaskAttachment 待建 |
| 云函数接收端 | ⬜ 未实现 |
| v2 处置 | 落接口层 + 空态,禁止伪造数据;字段形状按《ER-图-草案.md》§二.B,以 AgentTask 为真源 |
待核实的 6 组(见 docs/03-interface/待问Agent-20261014-多任务接入核实.md):assignee 取值域、
block_kind 枚举、priority 语义、branchName 来源、projectId 是否落库、startedAt 等时间字段口径。
| # | 端点 | 用途 | 关键点 |
|---|---|---|---|
| R1 | POST /parse/users/me |
Token 直登校验 + 取身份 | 头 X-Parse-Session-Token |
| R2 | GET /parse/roles?where={users:Pointer<_User>}&limit=50 |
补 roles 关系 |
🔴 _User JSON 不透出 relation,必须单独查(存量 v0.3.3 著名坑:超管因缺 roles 被误判为 company-member → 列表空) |
| R3 | PUT /parse/users/<id> |
校正 company 指针 |
❌ v2 禁止调用(改为服务端权威,见 §2.4) |
| R4 | POST /api/apig/message {mobile, company} |
发短信验证码 | 🔴 code === 1 才算成功(不是 200) |
| R5 | GET /api/fmode/mobile?mobile&code&company |
验证码登录 | 🔴 code === 200 && data.token 才算成功;data.newapiToken 另存备用 |
| R6 | GET /api/fmodeagent/status |
旧 REST 状态(降级路径) | v2 不采用(走云函数 xlosi3m46q) |
| R7 | GET /parse/classes/FmodeAgent?limit=200&include=user,company |
旧直查兜底 | v2 不采用 |
| 形态 | 用途 | 传递方式 |
|---|---|---|
r: 前缀的 Fmode SessionToken |
业务会话令牌 | 登录页强校验 r: 前缀;存 localStorage |
| Parse SessionToken | Parse REST / 云函数鉴权 | X-Parse-Session-Token 头 + body 的 token |
Matrix Bearer <accessToken> |
Matrix 客户端 | 由 RP5Ht55NeX 签发,仅存内存 + localStorage,不入代码 |
| 类 | 字段 | 说明 |
|---|---|---|
_User |
objectId username nickname mobile company(Pointer) roles(relation) newapiToken |
roles 需单独查(R2) |
_Role |
name |
命名约定 <companyId>_Admin;超管 = masters / FMODE_AGENT_SUPERADMIN |
Company |
objectId name |
登录公司常量 E4KpGvTEto |
FmodeAgent |
同 AgentStatusItem |
主路径不直查,走云函数 |
Deliverable |
— | ❌ 代码中不存在;成果全部走云函数 lfYlgU7SkK |
AgentTask / AgentTaskRun / AgentLiveEvent |
见 ER 草案 | 表已建;前端一期不消费 AgentLiveEvent |
AgentTaskComment / AgentTaskAttachment |
见 ER 草案 | ⬜ 待建 |
| 项 | 实情 |
|---|---|
isDeleted |
🔴 存量前端代码中 0 处出现(全量 grep 证实)。过滤完全依赖服务端云函数与 CLP/ACL |
company 指针 |
存在于表结构;前端写路径仅 PUT /users/<id>(v2 已禁止) |
| 写操作总数 | 仅 2 处:R3(company,已禁)与 xlosi3m46q 的 gender 写入 |
v2 处置:前端不做软删过滤与租户过滤(那是服务端 CLP 职责),但必须在类型与文档上标注该字段存在, 且不得新增前端直写路径。黄金规则 6 的"业务表必须带
company"由服务端 Schema 保证。
判级顺序(✅ 确定):
roles 含 'masters' | 'FMODE_AGENT_SUPERADMIN' → superadmin
username === 'FMODE_AGENT_SUPERADMIN' → superadmin
company && roles 含 '<companyId>_Admin' → company-admin
有 company → company-member
否则 → personal
🔴 FR-20 AC-20.2 硬约束:前端代码中无基于 roles 字段的授权分支(判据:grep 命中 0)。
roles 只用于:① 决定请求哪个 scope(期望值)② 界面提示。
可见范围判定一律由服务端返回;越权应返回 403 语义,不得返回空列表。
| # | 事项 | 影响 | 优先级 |
|---|---|---|---|
| 1 | zl4yU8PAEB 是否已改造为返回权威 company |
FR-02 AC-02.4 / NFR-04 | 🔴 高 |
| 2 | kanban 云函数接收端是否实现 | FR-07b 全模块 | 🔴 高 |
| 3 | AgentTaskComment / AgentTaskAttachment 两表是否建 |
FR-07b AC-07b.2 | 🔴 高 |
| 4 | xlosi3m46q 的 balance / usage 字段名与结构 |
FR-07 AC-07.1/07.2 | 🟡 中 |
| 5 | progress 数值语义(百分比 or 比例) |
工作台进度条 | 🟡 中 |
| 6 | 成果 status 取值域 |
成果状态徽标 | 🟡 中 |
| 7 | 越权返回码是否确为 403(而非 200 + 空) | FR-20 AC-20.3 | 🟡 中 |
| 8 | gender 取值域与是否需要保留该写操作 |
会话内性别询问流程 | ⬜ 低(建议 v2 移除) |
E:\work\fmode-app\src\app\core\parse-client.ts(只读参考)