tg_claw_kit接入指南
1. 简介
tg_claw_kit 是一个面向 Flutter 的龙虾实例 SDK,用于查询已绑定设备、查看当前画面、查询事件、查看事件图片、确认设备状态和电量等,主要功能有:
- 鉴权
- 会话管理(新建会话、会话列表、加载指定会话历史、删除会话)
- 流式对话
- 设备授权、解绑、授权列表查询
- 微信渠道扫码接入龙虾实例
- 定时任务创建、更新、查询、暂停、启动、删除和执行记录查询
前置申请
- 接入前请先向平台对接人员申请创建企业专属的Agent模板 ID, 例如:
templateId: 'template-abc123'。SDK 会将该值传给getClawTokenByToken,后续请求使用接口返回的sdkConfig.templateId。
2. 安装
在工程的根目录执行:
flutter pub add tg_claw_kit
这将在 pubspec.yaml 中添加:
dependencies:
tg_claw_kit: ^最新版本号
获取 tg_claw_kit 版本号: https://pub.dev/packages/tg_claw_kit/changelog
3. 初始化
在调用其他 API 之前先初始化 SDK。
await TgClawKit.initialize(
authAppId: 'your_app_id',
authPackageName: 'com.example.app',
templateId: 'template-abc123',
);
4. 鉴权
final TgClawSession session = await TgClawKit.auth(
accessToken: accessToken,
deviceId: deviceId
);
参数说明:
- accessToken为用户登录APP之后的token,用于SDK获取该用户的信息
- deviceId为该用户任意一台在tivs有claw套餐的设备ID,用于SDK确认套餐有效后给该用户新建claw实例进行对话
5. 会话管理
前提: 已完成 TgClawKit.initialize(...)和TgClawKit.auth(accessToken: ..., deviceId: ...)。
5.1 开启新会话
final String sessionId = await TgClawKit.startNewSession();
5.2 列举会话列表
final List<TgClawSessionSummary> sessions = await TgClawKit.listSessions(
);
5.3 加载指定会话历史
final TgClawChatHistory history = await TgClawKit.loadSessionHistory(
sessionId: sessionId,
);
5.4 删除会话
await TgClawKit.deleteSession(
sessionId: sessionId,
);
5.5 中止当前会话任务
用于用户主动取消正在生成或执行中的 Agent 任务。返回值表示服务端是否找到并中止了运行中的任务;false 通常表示该会话当前没有运行中的任务。
final bool stopped = await TgClawKit.stopSession(
sessionId: sessionId,
);
6. 发起会话
前提:在聊天前请先调用 startNewSession() 或 loadSessionHistory(sessionId: ...)。
await TgClawKit.chat(
'帮我总结最近一次设备告警',
onEvent: (TgClawChatEvent event) {
final TgClawMessage? message = event.snapshot;
if (message == null) {
return;
}
debugPrint('[${message.role.name}] ${message.text}');
},
);
onEvent 会持续返回增量事件,适合直接驱动聊天 UI。chat() 不提供单独的 onError / onDone 回调:
- 请求失败时会直接抛出
TgClawException - 流结束时会回调一个
TgClawChatEventType.finished事件
当前 event.type 的实际取值可以按下面这个枚举理解:
enum TgClawChatEventType {
messageStarted,
messageDelta,
messageCompleted,
reasoningDelta,
toolCallStarted,
toolCallCompleted,
finished,
}
各类型的具体语义如下:
| 类型 | 触发来源 | 含义 | 关键字段 |
|---|---|---|---|
messageStarted |
object=message 且 status=created/in_progress |
一条普通消息开始生成 | event.snapshot 存在,且 snapshot.streaming == true |
messageDelta |
object=content 且为普通文本增量 |
收到一段普通回复文本 | event.delta 是本次新增文本,event.snapshot.text 是累计后的完整文本 |
messageCompleted |
object=message 且 status=completed |
一条普通消息完成 | event.snapshot.streaming == false |
reasoningDelta |
object=content 且当前消息被识别为 reasoning |
收到一段思考过程文本 | event.snapshot.kind == TgClawMessageKind.reasoning |
toolCallStarted |
工具调用消息开始 | 一次工具调用开始执行 | event.snapshot.kind == TgClawMessageKind.toolCall |
toolCallCompleted |
工具调用结果完成 | 一次工具调用或工具输出完成 | event.snapshot.kind == TgClawMessageKind.toolOutput |
finished |
流式请求自然结束 | 本次流结束 | event.snapshot 通常为空 |
补充说明:
TgClawChatEvent的字段是type、messageId、snapshot、delta,没有message、sessionId、error字段。messageDelta和reasoningDelta都是内容级事件;前者用于普通回复,后者用于思考过程。initialize()传入的templateId会作为getClawTokenByToken的模板入参;鉴权成功后,SDK 后续会话/聊天请求会使用接口返回的sdkConfig.templateId。routingKey会透传到 Chat Body 参数RoutingKey。
7. 设备授权
授权设备:
final TgAuthorizeResult result = await TgClawKit.authorize(deviceId: deviceId);
解除授权:
final TgAuthorizeResult result = await TgClawKit.revoke(deviceId: deviceId);
查询已授权设备:
final List<TgAuthorizedDevice> devices =
await TgClawKit.getAuthorizationDevices();
授权结果状态定义:
enum TgAuthorizeStatus {
authorized,
alreadyAuthorized,
revoked,
alreadyRevoked,
}
其中:
authorize()成功返回authorized- 重复授权等幂等场景返回
alreadyAuthorized revoke()成功返回revoked- 重复解除授权或目标不存在等幂等场景返回
alreadyRevoked
8. 微信渠道接入龙虾实例
微信渠道用于让用户通过微信扫码,把当前用户对应的龙虾实例绑定到微信渠道,绑定成功后,微信侧会创建一个渠道实例,后续消息可以进入对应的 Agent。
前提: 已完成 TgClawKit.initialize(...)和TgClawKit.auth(accessToken: ..., deviceId: ...)。
8.1 创建微信扫码二维码
final TgClawWechatBindSession session =
await TgClawKit.createWechatChannelBindSession();
session 主要字段:
| 字段 | 说明 |
|---|---|
sessionKey |
扫码会话 Key,用于后续轮询绑定状态 |
qrCodeImageBase64 |
二维码 PNG 的 base64 data URL,可直接解码展示 |
qrCodeImageUrl |
微信二维码短链,主要用于留痕 |
expiresAt |
二维码过期时间 |
requestId |
后端或阿里请求 ID,便于排查问题 |
8.2 轮询绑定状态
推荐直接使用 SDK 提供的轮询流。默认每 2 秒查询一次,遇到 confirmed 或 expired 会自动结束。
await for (final TgClawWechatBindStatus status
in TgClawKit.watchWechatChannelBindStatus(
sessionKey: session.sessionKey,
)) {
if (status.state == TgClawWechatBindState.confirmed) {
debugPrint('微信渠道绑定成功: ${status.channelInstanceId}');
break;
}
if (status.state == TgClawWechatBindState.expired) {
debugPrint('二维码已过期: ${status.errorMessage}');
break;
}
}
状态定义:
enum TgClawWechatBindState {
waiting, // 等待扫码
scanned, // 已扫码,等待手机端确认
confirmed, // 绑定成功
expired, // 二维码过期或用户拒绝
unknown, // 未识别状态
}
8.3 查询、启用或禁用微信渠道实例
扫码绑定成功后即可管理当前微信渠道实例。业务上如需“禁用”当前微信接入,推荐将实例状态改为 disabled:禁用后该实例停止收发消息,但保留实例记录;需要恢复时再改回 enabled。
查询当前启用状态:
final TgClawChannelInstance currentChannel =
await TgClawKit.describeWechatChannelInstance();
debugPrint('微信渠道当前状态: ${currentChannel.status}');
final TgClawChannelInstance disabledChannel =
await TgClawKit.updateWechatChannelInstance(
status: 'disabled',
);
debugPrint('微信渠道已禁用: ${disabledChannel.status}');
重新启用:
final TgClawChannelInstance enabledChannel =
await TgClawKit.updateWechatChannelInstance(
status: 'enabled',
);
debugPrint('微信渠道已启用: ${enabledChannel.status}');
describeWechatChannelInstance / updateWechatChannelInstance 主要字段:
| 参数 | 说明 |
|---|---|
status |
目标状态,仅 updateWechatChannelInstance 需要传入,支持 enabled 或 disabled |
9. 定时任务
定时任务用于让当前用户的龙虾实例按指定时间自动执行一段 Agent 指令。
前提:已完成 TgClawKit.initialize(...) 和 TgClawKit.auth(accessToken: ..., deviceId: ...)。
9.1 创建定时任务
final TgClawScheduledTask task = await TgClawKit.createScheduledTask(
name: '每日设备巡检',
instruction: '检查设备在线状态、最近告警和电量,生成一段简短巡检摘要。',
schedule: <String, dynamic>{
'Type': 'cron',
'Expr': '0 9 * * *',
'Timezone': 'Asia/Shanghai',
},
);
debugPrint('创建成功: ${task.taskId}, 下次执行: ${task.nextRunAt}');
参数说明:
| 参数 | 必填 | 说明 |
|---|---|---|
name |
是 | 任务名称,不能为空 |
instruction |
是 | 每次触发时交给 Agent 执行的指令,不能为空 |
schedule |
是 | 调度配置,必须包含 Type 和 Expr |
schedule 支持以下类型:
Type |
Expr 示例 |
说明 |
|---|---|---|
cron |
0 9 * * * |
cron 表达式,建议同时传 Timezone |
interval |
10m / 2h |
固定间隔执行 |
once |
2026-05-08T15:00:00 |
指定时间执行一次 |
Type为cron的Expr 设置方式参照: https://help.aliyun.com/zh/auto-scaling/user-guide/overview-8
Timezone设置方式参照: https://help.aliyun.com/zh/maxcompute/user-guide/time-zones
9.2 更新定时任务
更新接口会用传入的 name、instruction、schedule 覆盖原任务配置;请先保留业务侧仍需要的字段,再提交更新。
final TgClawScheduledTask updated = await TgClawKit.updateScheduledTask(
taskId: task.taskId,
name: '每日设备巡检',
instruction: '检查设备在线状态、最近告警、电量,并输出异常项。',
schedule: <String, dynamic>{
'Type': 'cron',
'Expr': '30 9 * * *',
'Timezone': 'Asia/Shanghai',
},
);
debugPrint('更新成功: ${updated.taskId}');
9.3 查询任务详情
final TgClawScheduledTask detail = await TgClawKit.getScheduledTask(
taskId: task.taskId,
);
debugPrint('任务状态: ${detail.status}');
debugPrint('调度配置: ${detail.schedule}');
TgClawScheduledTask 主要字段:
| 字段 | 说明 |
|---|---|
taskId |
任务 ID,后续查询、更新、删除都使用它 |
templateId |
鉴权接口返回的 Agent 模板 ID |
externalUserId |
当前鉴权用户标识 |
name |
任务名称 |
status |
任务状态,以服务端返回为准 |
instruction |
任务触发时执行的 Agent 指令 |
schedule |
调度配置 Map |
nextRunAt |
下次计划执行时间,可能为空 |
lastRunAt |
最近一次执行时间,可能为空 |
lastError |
最近一次错误信息,可能为空 |
createdAt / updatedAt |
创建和更新时间 |
9.4 分页查询任务列表
final TgClawScheduledTaskPage page = await TgClawKit.listScheduledTasks(
pageNumber: 1,
pageSize: 20,
);
for (final task in page.tasks) {
debugPrint('${task.taskId}: ${task.name} ${task.status}');
}
TgClawScheduledTaskPage 字段:
| 字段 | 说明 |
|---|---|
tasks |
当前页任务列表 |
totalCount |
服务端返回的任务总数 |
pageNumber |
当前页码 |
pageSize |
当前页大小 |
9.5 暂停 / 启动定时任务
暂停后任务不再按计划触发;启动会恢复已暂停的任务,并继续使用原有调度配置。
final TgClawScheduledTask paused = await TgClawKit.pauseScheduledTask(
taskId: task.taskId,
);
debugPrint('暂停后状态: ${paused.status}');
final TgClawScheduledTask resumed = await TgClawKit.resumeScheduledTask(
taskId: task.taskId,
);
debugPrint('启动后状态: ${resumed.status}');
9.6 删除定时任务
final bool deleted = await TgClawKit.deleteScheduledTask(
taskId: task.taskId,
);
debugPrint(deleted ? '删除成功' : '未删除');
9.7 查询执行记录
不传 taskId 时查询当前用户当前模板下的全部执行记录;传入 taskId 时只查询指定任务的执行记录。
String cursor = '';
do {
final TgClawScheduledTaskRunPage runPage =
await TgClawKit.listScheduledTaskRuns(
taskId: task.taskId,
cursor: cursor,
pageSize: 50,
order: 'desc',
);
for (final run in runPage.runs) {
debugPrint('${run.runId}: ${run.status}');
}
cursor = runPage.nextCursor;
} while (cursor.isNotEmpty);
也可以通过 since / until 过滤执行记录。since 和 until 为毫秒时间戳,until 表示右闭区间 FinishedAt <= until;
order 支持 asc / desc,默认传 desc。
final int since = DateTime.now()
.subtract(const Duration(days: 1))
.millisecondsSinceEpoch;
final int until = DateTime.now().millisecondsSinceEpoch;
final TgClawScheduledTaskRunPage recentRuns =
await TgClawKit.listScheduledTaskRuns(
since: since,
until: until,
order: 'desc',
pageSize: 50,
);
TgClawScheduledTaskRun 主要字段:
| 字段 | 说明 |
|---|---|
runId |
执行记录 ID |
taskId |
对应的任务 ID |
status |
本次执行状态,以服务端返回为准 |
resultPayload |
本次执行结果内容 |
errorMessage |
本次执行错误信息 |
startedAt / finishedAt |
执行开始和结束时间 |
createdAt |
执行记录创建时间 |
9.8 错误处理建议
定时任务接口参数不合法或请求失败时会抛出 TgClawException。接入方建议统一捕获后展示 message,并在排查问题时记录 code 和 httpStatusCode。
try {
await TgClawKit.createScheduledTask(
name: name,
instruction: instruction,
schedule: schedule,
);
} on TgClawException catch (error) {
debugPrint(
'定时任务失败: code=${error.code}, '
'status=${error.httpStatusCode}, message=${error.message}',
);
}
SDK 本地会先校验以下错误:
code |
说明 |
|---|---|
not_initialized |
未先调用 initialize() |
task_name_empty |
name 为空 |
task_instruction_empty |
instruction 为空 |
task_id_empty |
taskId 为空 |
task_schedule_type_invalid |
schedule.Type 不是 cron、interval、once |
task_schedule_expr_empty |
schedule.Expr 为空 |
HTTP 请求失败时会按接口返回对应的 *_scheduled_task_http_error 错误码,例如 create_scheduled_task_http_error、pause_scheduled_task_http_error、resume_scheduled_task_http_error、list_scheduled_task_runs_http_error。
10. 建议接入方式
推荐调用顺序:
await TgClawKit.initialize(
authAppId: 'your_app_id',
authPackageName: 'com.example.app',
templateId: 'template-abc123',
);
await TgClawKit.auth(
accessToken: accessToken,
deviceId: deviceId
);
// 默认进入聊天页时创建新会话
final sessionId = await TgClawKit.startNewSession();
await TgClawKit.chat(
'你好',
onEvent: (event) {},
);
// 或从历史会话恢复
final sessions = await TgClawKit.listSessions();
if (sessions.isNotEmpty) {
await TgClawKit.loadSessionHistory(
sessionId: sessions.first.sessionId,
);
}
// 可选流程:如需微信扫码接入,创建绑定二维码并等待用户扫码结束。
// 注意: 微信绑定只依赖于initialize()和auth(),不要求先调用 `startNewSession() 或者loadSessionHistory()`,只有进入聊天页发起对话时,才需要新建或恢复会话。
final bindSession = await TgClawKit.createWechatChannelBindSession();
await for (final status in TgClawKit.watchWechatChannelBindStatus(
sessionKey: bindSession.sessionKey,
)) {
if (status.state == TgClawWechatBindState.confirmed) {
break;
}
if (status.state == TgClawWechatBindState.expired) {
throw TgClawException(
code: status.errorCode.isEmpty ? 'wechat_qr_expired' : status.errorCode,
message: status.errorMessage.isEmpty
? '二维码已过期,请重新生成'
: status.errorMessage,
);
}
}
// 可选流程:如需定时任务,完成 initialize() 和 auth() 后即可创建或管理。
final scheduledTask = await TgClawKit.createScheduledTask(
name: '每日设备巡检',
instruction: '检查设备状态并总结异常项。',
schedule: <String, dynamic>{
'Type': 'cron',
'Expr': '0 9 * * *',
'Timezone': 'Asia/Shanghai',
},
);
11. 环境切换
支持环境切换,环境枚举以实际代码为准:
await TgClawKit.initialize(
authAppId: 'your_app_id',
authPackageName: 'com.example.app',
templateId: 'template-abc123',
environment: TgClawEnvironment.prod, // prod | pre | test
runtimeLoggingEnabled: false,
);
12. 完整示例
插件仓库内置了 example 工程,直接演示:
- 登录
- 创建新会话
- 左侧半屏会话面板(新建/切换/删除会话)
- 流式聊天
- 设备授权与解绑
- 微信渠道扫码接入龙虾实例
- 定时任务管理
- 环境切换
建议先运行 example,确认业务账号和环境配置后,再接入正式工程。