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=messagestatus=created/in_progress 一条普通消息开始生成 event.snapshot 存在,且 snapshot.streaming == true
messageDelta object=content 且为普通文本增量 收到一段普通回复文本 event.delta 是本次新增文本,event.snapshot.text 是累计后的完整文本
messageCompleted object=messagestatus=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 的字段是 typemessageIdsnapshotdelta,没有 messagesessionIderror 字段。
  • messageDeltareasoningDelta 都是内容级事件;前者用于普通回复,后者用于思考过程。
  • initialize() 传入的 templateId 会作为 getClawTokenByToken 的模板入参;鉴权成功后,SDK 后续会话/聊天请求会使用接口返回的 sdkConfig.templateIdroutingKey 会透传到 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 秒查询一次,遇到 confirmedexpired 会自动结束。

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 需要传入,支持 enableddisabled

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 调度配置,必须包含 TypeExpr

schedule 支持以下类型:

Type Expr 示例 说明
cron 0 9 * * * cron 表达式,建议同时传 Timezone
interval 10m / 2h 固定间隔执行
once 2026-05-08T15:00:00 指定时间执行一次

Type为cronExpr 设置方式参照: https://help.aliyun.com/zh/auto-scaling/user-guide/overview-8

Timezone设置方式参照: https://help.aliyun.com/zh/maxcompute/user-guide/time-zones

9.2 更新定时任务

更新接口会用传入的 nameinstructionschedule 覆盖原任务配置;请先保留业务侧仍需要的字段,再提交更新。

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 过滤执行记录。sinceuntil 为毫秒时间戳,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,并在排查问题时记录 codehttpStatusCode

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 不是 cronintervalonce
task_schedule_expr_empty schedule.Expr 为空

HTTP 请求失败时会按接口返回对应的 *_scheduled_task_http_error 错误码,例如 create_scheduled_task_http_errorpause_scheduled_task_http_errorresume_scheduled_task_http_errorlist_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,确认业务账号和环境配置后,再接入正式工程。

Libraries

tg_claw_kit