secondme-reference

SecondMe API 技术参考文档,供开发时查阅

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "secondme-reference" with this command: npx skills add mindverse/second-me-skills/mindverse-second-me-skills-secondme-reference

SecondMe API 技术参考

本文档包含 SecondMe API 的完整技术参考信息,供开发时查阅。


API 基础 URL

https://api.mindverse.com/gate/lab

OAuth2 授权 URL

https://go.second.me/oauth/

OAuth2 流程

1. 用户点击登录 → 跳转到 SecondMe 授权页面
2. 用户授权 → 重定向回你的应用(带 authorization_code)
3. 后端用 code 换取 access_token 和 refresh_token
4. 使用 access_token 调用 SecondMe API
5. Token 过期时使用 refresh_token 刷新

授权 URL 构造

重要:oauth_url 已包含完整路径,直接在后面拼接 ? 和查询参数即可,不要追加 /authorize 等路径。

const OAUTH_URL = 'https://go.second.me/oauth/';

const params = new URLSearchParams({
  client_id: process.env.SECONDME_CLIENT_ID,
  redirect_uri: process.env.SECONDME_REDIRECT_URI,
  response_type: 'code',
  state: generatedState,
});

// ✅ 正确:直接拼接 ? 和参数
const authUrl = `${OAUTH_URL}?${params.toString()}`;
// 结果: https://go.second.me/oauth/?client_id=...&redirect_uri=...

// ❌ 错误:不要追加 /authorize 等路径
// const authUrl = `${OAUTH_URL}/authorize?${params}`;
// 会变成: https://go.second.me/oauth//authorize?... ❌

Token 交换(用授权码换 Token)

端点

POST {base_url}/api/oauth/token/code

请求格式

Content-Type 必须是 application/x-www-form-urlencoded,不是 JSON。

const response = await fetch(`${API_BASE_URL}/api/oauth/token/code`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',  // 必须
  },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: authorizationCode,
    redirect_uri: process.env.SECONDME_REDIRECT_URI,
    client_id: process.env.SECONDME_CLIENT_ID,
    client_secret: process.env.SECONDME_CLIENT_SECRET,
  }),
});

响应格式

响应遵循统一包装格式,字段使用 camelCase(不是 OAuth2 标准的 snake_case):

{
  "code": 0,
  "data": {
    "accessToken": "lba_at_xxxxx...",
    "refreshToken": "lba_rt_xxxxx...",
    "tokenType": "Bearer",
    "expiresIn": 7200,
    "scope": ["user.info", "chat"]
  }
}

响应处理

const result = await response.json();

// 必须检查 code 字段
if (result.code !== 0 || !result.data) {
  throw new Error(`Token exchange failed: ${result.message}`);
}

// 从 data 中提取,使用 camelCase
const { accessToken, refreshToken, expiresIn } = result.data;

Token 刷新

端点

POST {base_url}/api/oauth/token/refresh

请求格式

const response = await fetch(`${API_BASE_URL}/api/oauth/token/refresh`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
  body: new URLSearchParams({
    grant_type: 'refresh_token',
    refresh_token: storedRefreshToken,
    client_id: process.env.SECONDME_CLIENT_ID,
    client_secret: process.env.SECONDME_CLIENT_SECRET,
  }),
});

响应格式与 Token 交换一致。


Token 有效期

Token 类型前缀有效期
授权码lba_ac_5 分钟
Access Tokenlba_at_2 小时
Refresh Tokenlba_rt_30 天

权限列表(Scopes)

权限说明
user.info用户基础信息
user.info.shades用户兴趣标签
user.info.softmemory用户软记忆
note.add添加笔记
chat聊天功能
chat结构化动作判断(Act)

API 响应格式与处理

重要:所有 SecondMe API 响应都遵循统一格式:

{
  "code": 0,
  "data": { ... }  // 实际数据在 data 字段内
}

前端代码必须正确提取数据:

// 注意:以下 /api/secondme/... 是 Next.js 本地路由(由 secondme-nextjs skill 生成),
// 本地路由会代理请求到上游 SecondMe API,并透传上游的响应格式。

// ❌ 错误写法 - 直接使用响应会导致 .map is not a function
const response = await fetch('/api/secondme/user/shades');  // Next.js 本地路由
const shades = await response.json();
shades.map(item => ...)  // 错误!

// ✅ 正确写法 - 提取 data 字段内的数据
const response = await fetch('/api/secondme/user/shades');  // Next.js 本地路由
const result = await response.json();
if (result.code === 0) {
  const shades = result.data.shades;  // 正确!
  shades.map(item => ...)
}

各 API 的数据路径

以下路径均为上游 SecondMe API 路径,完整 URL = {base_url}/api/secondme{path} 其中 base_url 来自 state.api.base_url(默认 https://api.mindverse.com/gate/lab

上游 API 路径数据路径类型
/api/secondme/user/inforesult.dataobject(含 email, name, avatarUrl, route 等字段)
/api/secondme/user/shadesresult.data.shadesarray
/api/secondme/user/softmemoryresult.data.listarray
/api/secondme/chat/session/listresult.data.sessionsarray
/api/secondme/chat/session/messagesresult.data.messagesarray
/api/secondme/act/streamSSE 流式 JSON(需拼接 delta)SSE stream
/api/secondme/note/addresult.data.noteIdnumber
/api/secondme/agent_memory/ingestresult.data.eventId / result.data.isDuplicateobject

Act API(结构化动作判断)

Act API 是独立于 Chat API 的接口,约束模型仅输出合法 JSON 对象,适用于情感分析、意图分类等结构化决策场景。权限使用 chat scope。

端点(上游 API)

POST {base_url}/api/secondme/act/stream

请求参数

参数类型必需说明
messagestring用户消息内容
actionControlstring动作控制说明(20-8000 字符),定义 JSON 结构与判断规则
appIdstring应用 ID
sessionIdstring会话 ID,不提供则自动生成
systemPromptstring系统提示词,仅新会话首次有效

actionControl 示例

仅输出合法 JSON 对象,不要解释。
输出结构:{"is_liked": boolean}。
当用户明确表达喜欢或支持时 is_liked=true,否则 is_liked=false。

响应格式(SSE)

event: session
data: {"sessionId": "labs_sess_xxx"}

data: {"choices": [{"delta": {"content": "{\"is_liked\": true}"}}]}

data: [DONE]

前端处理示例

// 调用 Act API 进行结构化判断(通过 Next.js 本地路由代理到上游)
const response = await fetch('/api/secondme/act/stream', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    message: userMessage,
    actionControl: '仅输出合法 JSON。结构:{"intent": "like"|"dislike"|"neutral"}。根据用户表达判断意图。信息不足时返回 {"intent": "neutral"}。'
  })
});

// 拼接 SSE 流中的 delta content,最终 JSON.parse 得到结果

Chat vs Act 使用场景

场景使用 API原因
自由对话/chat/stream返回自然语言文本
情感/意图判断/act/stream返回结构化 JSON
是/否决策/act/stream返回 {"result": boolean}
多分类判断/act/stream返回 {"category": "..."}
内容生成/chat/stream需要长文本输出

Agent Memory API(事件上报与查询)

Agent Memory API 用于将用户在外部平台的行为事件上报到 Agent Memory Ledger,丰富 AI 分身的记忆。认证方式与其他 SecondMe API 一致(OAuth2 Token),不需要特定 scope

上报端点

POST {base_url}/api/secondme/agent_memory/ingest

请求参数

参数类型必需说明
channelChannelInfo频道信息
actionstring动作类型
refsRefItem[]证据指针数组(至少 1 项)
actionLabelstring动作展示文案
displayTextstring用户可读摘要
eventDescstring开发者描述
eventTimeinteger事件时间戳(毫秒)
importancenumber重要性 0.0~1.0
idempotencyKeystring幂等键
payloadobject扩展信息

嵌套类型

ChannelInfo: { kind: string, id?: string, url?: string, meta?: object }

platform 由服务端根据应用 Client ID 自动填充,前端无需传入。

RefItem: { objectType: string, objectId: string, type?: string, url?: string, contentPreview?: string, snapshot?: RefSnapshot }

RefSnapshot: { text: string, capturedAt?: number, hash?: string }

幂等键生成规则

前端应生成幂等键防止重复上报(参照 plaza 前端实现):

// 规则: sha256("external:" + objectType + ":" + objectId)
// 注意:platform 和 userId 由后端自动填充,前端无需关心
import { sha256 } from 'some-hash-lib';

function generateIdempotencyKey(objectType: string, objectId: string): string {
  return sha256(`external:${objectType}:${objectId}`);
}

常见 action 类型

action说明典型场景
post_created发帖用户在广场发布新帖子
reply回帖用户回复某个帖子
ai_replyAI 回帖AI 分身自动回复帖子
find_people找人用户搜索其他用户
replied被回帖用户的帖子被他人回复
post_viewed看帖用户浏览帖子
user_liked点赞用户点赞某内容
liked被赞用户的内容被他人点赞

响应格式

{
  "code": 0,
  "data": {
    "eventId": 123,
    "isDuplicate": false
  }
}

前端集成示例(TypeScript)

interface ChannelInfo {
  kind: string;
  id?: string;
  url?: string;
  meta?: Record<string, unknown>;
}

interface RefItem {
  objectType: string;
  objectId: string;
  type?: string;
  url?: string;
  contentPreview?: string;
  snapshot?: { text: string; capturedAt?: number; hash?: string };
}

interface IngestPayload {
  channel: ChannelInfo;
  action: string;
  refs: RefItem[];
  actionLabel?: string;
  displayText?: string;
  eventTime?: number;
  importance?: number;
  idempotencyKey?: string;
  payload?: Record<string, unknown>;
}

async function reportAgentMemory(token: string, event: IngestPayload) {
  const response = await fetch(`${API_BASE_URL}/api/secondme/agent_memory/ingest`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(event),
  });
  const result = await response.json();
  if (result.code !== 0) {
    throw new Error(`Ingest failed: ${result.message}`);
  }
  return result.data; // { eventId: number, isDuplicate: boolean }
}

错误码

错误码HTTP说明
agent_memory.write.disabled403用户的 Agent Memory 写入已禁用
agent_memory.ingest.failed502上报失败

开发注意事项

State 参数

直接忽略 state 参数验证。 在回调处理时不需要验证 state,直接处理授权码即可。

CSS @import 规则顺序

重要: 在 CSS 文件中,@import 语句必须放在文件的最开头(只能在 @charset@layer 之后)。如果在其他 CSS 规则之后使用 @import,会导致解析错误。

/* 正确写法 - @import 放在最前面 */
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC&display=swap');

:root {
  --primary-color: #000;
}

/* 错误写法 - @import 不能放在其他规则之后 */
:root {
  --primary-color: #000;
}
@import url('...'); /* 这会报错! */

官方文档链接

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

secondme-nextjs

No summary provided by upstream source.

Repository SourceNeeds Review
General

secondme-prd

No summary provided by upstream source.

Repository SourceNeeds Review
General

secondme-init

No summary provided by upstream source.

Repository SourceNeeds Review