| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- // Copyright (c) 未来飞马
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
- //
- // Trademark Notice:
- // The MPL-2.0 license grants copyright permissions for source code only.
- // It does NOT grant any rights to use trademarks including "未来飞马",
- // "Harness Loop", "RSI", and associated slogan "让AI进化提前发生,让AI落地快人一步".
- // Any use of these trademarks requires separate written permission.
- /**
- * 交付物上报云函数(skill-deliverable 配套)
- * ============================================
- *
- * 部署:Parse.Cloud.define 或 /api/functions 模式
- * 云函数 ID:lfYlgU7SkK(保持不变)
- *
- * v2 变更:
- * 1. 移除 FMODE_AGENT_SUPERADMIN 角色检查 → 改为:用户仅对自有容器有上报权限
- * 2. agentId → agentObjectId 自动解析(传任一即可,缺失则自动补全)
- * 3. 首次上报时自动创建 FmodeAgent 记录(自注册)
- * 4. 参数缺失时自动补全(时间戳、状态等)
- *
- * 鉴权逻辑(简化版):
- * sessionToken → _User → 查此用户是否是该 FmodeAgent 记录的 owner
- * 是 → 允许上报;否 → 403
- * 若 FmodeAgent 记录不存在且 agentId 有效 → 自动创建 + 设当前用户为 owner
- */
- const CLASS_DELIVERABLE = 'AgentDeliverable';
- const CLASS_AGENT = 'FmodeAgent';
- Parse.Cloud.define('deliverable-report', async (req) => {
- const { agentId, agentObjectId, title, summary, project, artifacts, tags } = req.params;
- const user = req.user;
- if (!user) throw new Parse.Error(401, '需要登录');
- if (!title) throw new Parse.Error(400, 'title 必填');
- // ---- Step 1: 解析/注册 FmodeAgent ----
- let agentQuery = new Parse.Query(CLASS_AGENT);
-
- if (agentObjectId) {
- agentQuery.equalTo('objectId', agentObjectId);
- } else if (agentId) {
- agentQuery.equalTo('agentId', agentId);
- } else {
- throw new Parse.Error(400, 'agentId 或 agentObjectId 必填');
- }
- let agent = await agentQuery.first({ useMasterKey: true });
- // 自动注册:agent 不存在则创建
- if (!agent) {
- if (!agentId) throw new Parse.Error(400, '新 agent 注册需要 agentId');
- const AgentClass = Parse.Object.extend(CLASS_AGENT);
- agent = new AgentClass();
- agent.set('agentId', agentId);
- agent.set('user', user);
- agent.set('status', 'online');
- agent.set('heartbeatAt', new Date());
- agent = await agent.save(null, { useMasterKey: true });
- }
- const finalAgentId = agent.get('agentId') || agentId;
- const finalAgentOid = agent.id;
- // ---- Step 2: 权限校验(仅校验用户是否为 agent owner)----
- const agentUser = agent.get('user');
- if (agentUser && agentUser.id !== user.id) {
- throw new Parse.Error(403, '仅该容器的 owner 可上报');
- }
- // 如果 agent 没有 owner(旧数据),自动绑定当前用户
- if (!agentUser) {
- agent.set('user', user);
- await agent.save(null, { useMasterKey: true });
- }
- // ---- Step 3: 写入交付物 ----
- const DelClass = Parse.Object.extend(CLASS_DELIVERABLE);
- const record = new DelClass();
- record.set('agentId', finalAgentId);
- record.set('agent', agent); // 指针
- record.set('agentObjectId', finalAgentOid);
- record.set('user', user);
- record.set('title', title);
- record.set('summary', summary || '');
- record.set('project', project || '');
- record.set('artifacts', artifacts || []);
- record.set('tags', tags || []);
- record.set('reportedAt', new Date());
-
- // ACL:仅 owner 可读写
- const acl = new Parse.ACL(user);
- acl.setPublicReadAccess(false);
- acl.setPublicWriteAccess(false);
- record.setACL(acl);
- const saved = await record.save(null, { useMasterKey: true });
- // ---- Step 4: 更新 agent 心跳 ----
- agent.set('heartbeatAt', new Date());
- agent.set('status', 'online');
- await agent.save(null, { useMasterKey: true });
- return {
- code: 200,
- id: saved.id,
- agentId: finalAgentId,
- agentObjectId: finalAgentOid,
- title: title,
- createdAt: saved.get('createdAt') || saved.createdAt,
- };
- });
|