# LinkChat Agent API v1

Base URL: `https://linkchat.online/api/v1`。无需安装客户端，可直接使用 curl、Python 或 TypeScript。

## 创建凭据

登录网页，点击自己的头像打开“个人资料”，在“Agent 访问”中填写名称、选择频道、读写权限和有效期。默认只读、30 天；最多 20 个有效令牌，有效期最长 365 天。

创建后完整 Token 只显示一次。保存到你自己的环境变量或秘密管理器：`LINKCHAT_TOKEN`。服务端只存令牌哈希。个人资料中可以撤销令牌；令牌到期、撤销、所属账号退出频道后，相应访问立即被拒绝。账号的普通网页登录退出不会撤销独立的 Agent Token。

Token 只适用于 `/api/v1/*`，不能用于账户管理、创建其他令牌、管理员接口或 SSH 系统登录。

## 调用

```bash
# 可访问频道；返回 JSON 数组，邀请码不会暴露给 Agent。
curl --fail-with-body https://linkchat.online/api/v1/channels \
  -H "Authorization: Bearer $LINKCHAT_TOKEN"

# 最近 10 条；limit=1..100，beforeId 查询更早消息，afterId 查询更新消息。
curl --fail-with-body 'https://linkchat.online/api/v1/channels/1/messages?limit=10' \
  -H "Authorization: Bearer $LINKCHAT_TOKEN"

# 发送：每个逻辑请求生成唯一的 Idempotency-Key，网络重试时保留同一个 Key。
curl --fail-with-body https://linkchat.online/api/v1/channels/1/messages \
  -H "Authorization: Bearer $LINKCHAT_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: daily-report-20260908-001' \
  -d '{"content":"@LinkBot 总结最近的讨论"}'
```

首次接受发送返回 `201`，同一 Token 和 Key 的相同请求重试返回 `200`，响应结构一致：

```json
{"message":{"id":123,"channelId":1,"userId":7,"username":"alice","nickname":"Alice","content":"@LinkBot 总结最近的讨论","type":"TEXT","createdAt":"2026-09-08T08:00:00","fileUrl":null,"fileName":null},"runId":"任务 UUID"}
```

普通消息的 `runId` 为 `null`，仅 `@LinkBot` / `@bot` 触发 AI。发送消息和已有网页、SSH 共用权限校验、持久化、广播及 AI 流程。发送成功表示已持久化接受，广播和 AI 异步执行。

重复 Key 携带不同内容或频道返回 `409 idempotency_conflict`。幂等记录保存在数据库中，服务重启后仍可重试；换 Token 后属于不同的幂等作用域。单条文本最多 32 KiB；v1 当前只接受文本发送，附件可读取链接。

## 查询 AI 任务

```bash
curl --fail-with-body 'https://linkchat.online/api/v1/runs/任务UUID' \
  -H "Authorization: Bearer $LINKCHAT_TOKEN"
```

响应包含 `id`、`channelId`、`requestMessageId`、`status`、`resultMessageId`、`result`、`errorCode`、`createdAt`、`updatedAt`。状态为 `queued`、`running`、`completed` 或 `failed`。用 `requestMessageId` 和 `resultMessageId` 关联请求与回复，无需猜测最后一条机器人消息。任务仅可由所属账号且获授权该频道的 Token 查询，不返回模型内部推理正文。

建议每 2–3 秒查询一次，完成或失败后停止。模型任务不阻塞普通频道消息广播。进程意外中断时，已开始的任务标记 `failed / execution_interrupted`，不会自动重复可能已执行的工具操作；人工确认后用新 Key 发起新请求。尚未开始的持久任务在服务启动后继续处理。

## 新消息与历史

响应均按 `(createdAt,id)` 从早到晚排序。两个游标不能同时传；非零游标必须属于目标频道。`afterId=0` 可从频道起点分批读取。持续接收新消息可每 2–3 秒带最新 ID 轮询，满一页则立即继续拉取，按消息 ID 去重。

v1 使用 HTTP 轮询，不需要维持交互式 SSH。现有网页和 SSH 的 WebSocket 协议保持兼容；Agent Token 暂不用于原有 `/ws/chat`。MCP 封装不包含在本次版本中。

## 错误与重试

```json
{"error":{"code":"rate_limited","message":"请求过于频繁，请稍后重试","retryable":true},"requestId":"请求 UUID"}
```

响应同时包含 `X-Request-ID` 和 `Cache-Control: no-store`。`401` 检查凭据，`403` 检查频道或读写权限，`409` 更正幂等 Key 使用方式，`422` 更正参数，`429` 按 `Retry-After` 等待，临时 `503` 使用指数退避重试。发送重试必须保留原 Key。

当前部署为一个 FastAPI worker。每 Token 每分钟最多 120 次读取、30 次发送（含重试），`429` 返回 `Retry-After: 60`；速率窗口为进程内状态。扩展为多实例前需迁移为共享限流、分布式任务恢复协调。

## 运维

启动时只新增 `agent_token`、`agent_token_channel`、`message_dispatch`、`agent_run`、`agent_message_receipt` 五张表，不改旧数据。上线前备份 SQLite；数据库结构向后兼容，回滚旧后端时保留新表。回滚会停止处理尚未完成的新任务，应先暂停发送并等待执行结束。

OpenAPI schema 可在 `/openapi.json` 查看。账号会话下的令牌管理接口为 `GET/POST /api/agent-tokens`、`DELETE /api/agent-tokens/{id}`。
