openclaw-dcgchat 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # OpenClaw DCG Chat 插件
2
+
3
+ 连接 OpenClaw 与 DCG Chat 产品的通道插件。
4
+
5
+ ## 架构
6
+
7
+ ```
8
+ ┌──────────┐ WebSocket ┌──────────────┐ WebSocket ┌─────────────────────┐
9
+ │ Web 前端 │ ←───────────────→ │ 公司后端服务 │ ←───────────────→ │ OpenClaw(工作电脑) │
10
+ └──────────┘ └──────────────┘ (OpenClaw 主动连) └─────────────────────┘
11
+ ```
12
+
13
+ - OpenClaw 插件**主动连接**后端的 WebSocket 服务(不需要公网 IP)
14
+ - 后端收到用户消息后转发给 OpenClaw,OpenClaw 回复后发回后端
15
+
16
+ ## 快速开始
17
+
18
+ ### 1. 安装插件
19
+
20
+ ```bash
21
+ pnpm openclaw plugins install -l /path/to/openclaw-dcgchat
22
+ ```
23
+
24
+ ### 2. 配置
25
+
26
+ ```bash
27
+ openclaw config set channels.dcgchat.enabled true
28
+ openclaw config set channels.dcgchat.wsUrl "ws://your-backend:8080/openclaw/ws"
29
+ ```
30
+
31
+ ### 3. 启动
32
+
33
+ ```bash
34
+ pnpm openclaw gateway
35
+ ```
36
+
37
+ ## 消息协议(MVP)
38
+
39
+ ### 下行:后端 → OpenClaw(用户消息)
40
+
41
+ ```json
42
+ { "type": "message", "userId": "user_001", "text": "你好" }
43
+ ```
44
+
45
+ ### 上行:OpenClaw → 后端(Agent 回复)
46
+
47
+ ```json
48
+ { "type": "reply", "userId": "user_001", "text": "你好!有什么可以帮你的?" }
49
+ ```
50
+
51
+ ## 配置项
52
+
53
+ | 配置键 | 类型 | 说明 |
54
+ |--------|------|------|
55
+ | `channels.dcgchat.enabled` | boolean | 是否启用 |
56
+ | `channels.dcgchat.wsUrl` | string | 后端 WebSocket 地址 |
57
+
58
+ ## 开发
59
+
60
+ ```bash
61
+ # 安装依赖
62
+ pnpm install
63
+
64
+ # 类型检查
65
+ pnpm typecheck
66
+ ```
67
+
68
+ ## 文件结构
69
+
70
+ - `index.ts` - 插件入口
71
+ - `src/channel.ts` - ChannelPlugin 定义
72
+ - `src/runtime.ts` - 插件 runtime
73
+ - `src/types.ts` - 类型定义
74
+ - `src/monitor.ts` - WebSocket 连接与断线重连
75
+ - `src/bot.ts` - 消息处理与 Agent 调用
76
+
77
+ ## 后续迭代
78
+
79
+ - [ ] Token 认证
80
+ - [ ] 流式输出
81
+ - [ ] Typing 指示
82
+ - [ ] messageId 去重
83
+ - [ ] 错误消息类型
package/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
3
+ import { dcgchatPlugin } from "./src/channel.js";
4
+ import { setDcgchatRuntime } from "./src/runtime.js";
5
+
6
+ const plugin = {
7
+ id: "dcgchat",
8
+ name: "DCG Chat",
9
+ description: "连接 OpenClaw 与 DCG Chat 产品(WebSocket)",
10
+ configSchema: emptyPluginConfigSchema(),
11
+ register(api: OpenClawPluginApi) {
12
+ setDcgchatRuntime(api.runtime);
13
+ api.registerChannel({ plugin: dcgchatPlugin });
14
+ },
15
+ };
16
+
17
+ export default plugin;
@@ -0,0 +1,9 @@
1
+ {
2
+ "id": "dcgchat",
3
+ "channels": ["dcgchat"],
4
+ "configSchema": {
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "properties": {}
8
+ }
9
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "openclaw-dcgchat",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "OpenClaw channel plugin for DCG Chat (WebSocket)",
6
+ "main": "index.ts",
7
+ "license": "MIT",
8
+ "files": ["index.ts", "src", "openclaw.plugin.json"],
9
+ "keywords": ["openclaw", "dcgchat", "websocket", "ai"],
10
+ "scripts": {
11
+ "typecheck": "tsc --noEmit"
12
+ },
13
+ "dependencies": {
14
+ "ws": "^8.18.0"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^22.0.0",
18
+ "@types/ws": "^8.5.0",
19
+ "openclaw": "2026.1.29",
20
+ "typescript": "^5.7.0"
21
+ },
22
+ "peerDependencies": {
23
+ "openclaw": ">=2026.1.29"
24
+ },
25
+ "openclaw": {
26
+ "extensions": [
27
+ "./index.ts"
28
+ ],
29
+ "channel": {
30
+ "id": "dcgchat",
31
+ "label": "DCG Chat",
32
+ "selectionLabel": "DCG Chat",
33
+ "docsPath": "/channels/dcgchat",
34
+ "docsLabel": "dcgchat",
35
+ "blurb": "连接 OpenClaw 与 DCG Chat 产品",
36
+ "order": 80
37
+ },
38
+ "install": {
39
+ "npmSpec": "openclaw-dcgchat",
40
+ "localPath": ".",
41
+ "defaultChoice": "local"
42
+ }
43
+ }
44
+ }
package/src/bot.ts ADDED
@@ -0,0 +1,123 @@
1
+ import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk";
2
+ import { createReplyPrefixContext } from "openclaw/plugin-sdk";
3
+ import type { InboundMessage, OutboundReply } from "./types.js";
4
+ import { getDcgchatRuntime } from "./runtime.js";
5
+ import { resolveAccount } from "./channel.js";
6
+
7
+ /**
8
+ * 处理一条用户消息,调用 Agent 并返回回复
9
+ */
10
+ export async function handleDcgchatMessage(params: {
11
+ cfg: ClawdbotConfig;
12
+ msg: InboundMessage;
13
+ accountId: string;
14
+ runtime?: RuntimeEnv;
15
+ }): Promise<OutboundReply> {
16
+ const { cfg, msg, accountId, runtime } = params;
17
+ const log = runtime?.log ?? console.log;
18
+ const error = runtime?.error ?? console.error;
19
+
20
+ const account = resolveAccount(cfg, accountId);
21
+ const userId = msg._userId.toString();
22
+ // const text = msg.text?.trim();
23
+ const text = msg.content.text?.trim();
24
+
25
+ if (!userId || !text) {
26
+ return { type: "reply", userId: userId || "unknown", text: "[错误] 消息格式不正确" };
27
+ }
28
+
29
+ try {
30
+ const core = getDcgchatRuntime();
31
+
32
+ const route = core.channel.routing.resolveAgentRoute({
33
+ cfg,
34
+ channel: "dcgchat",
35
+ accountId: account.accountId,
36
+ peer: { kind: "direct", id: userId },
37
+ });
38
+
39
+ const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(cfg);
40
+ const messageBody = `${userId}: ${text}`;
41
+ const bodyFormatted = core.channel.reply.formatAgentEnvelope({
42
+ channel: "DCG Chat",
43
+ from: userId,
44
+ timestamp: new Date(),
45
+ envelope: envelopeOptions,
46
+ body: messageBody,
47
+ });
48
+
49
+ const ctxPayload = core.channel.reply.finalizeInboundContext({
50
+ Body: bodyFormatted,
51
+ RawBody: text,
52
+ CommandBody: text,
53
+ From: userId,
54
+ To: `user:${userId}`,
55
+ SessionKey: route.sessionKey,
56
+ AccountId: route.accountId,
57
+ ChatType: "direct",
58
+ SenderName: userId,
59
+ SenderId: userId,
60
+ Provider: "dcgchat" as const,
61
+ Surface: "dcgchat" as const,
62
+ MessageSid: `dcg-${Date.now()}-${userId}`,
63
+ Timestamp: Date.now(),
64
+ WasMentioned: true,
65
+ CommandAuthorized: true,
66
+ OriginatingChannel: "dcgchat" as const,
67
+ OriginatingTo: `user:${userId}`,
68
+ });
69
+
70
+ const prefixContext = createReplyPrefixContext({ cfg, agentId: route.agentId });
71
+ const replyChunks: string[] = [];
72
+
73
+ const { dispatcher, replyOptions, markDispatchIdle } =
74
+ core.channel.reply.createReplyDispatcherWithTyping({
75
+ responsePrefix: prefixContext.responsePrefix,
76
+ responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
77
+ humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
78
+ onReplyStart: async () => {},
79
+ deliver: async (payload) => {
80
+ const t = payload.text?.trim();
81
+ if (t) replyChunks.push(t);
82
+ },
83
+ onError: (err, info) => {
84
+ error(`dcgchat[${accountId}] ${info.kind} reply failed: ${String(err)}`);
85
+ },
86
+ onIdle: () => {},
87
+ });
88
+
89
+ log(`dcgchat[${accountId}]: dispatching to agent (session=${route.sessionKey})`);
90
+
91
+ await core.channel.reply.dispatchReplyFromConfig({
92
+ ctx: ctxPayload,
93
+ cfg,
94
+ dispatcher,
95
+ replyOptions: {
96
+ ...replyOptions,
97
+ onModelSelected: prefixContext.onModelSelected,
98
+ },
99
+ });
100
+
101
+ markDispatchIdle();
102
+
103
+ const reply = replyChunks.join("\n\n").trim();
104
+ log(`dcgchat[${accountId}]: dispatch complete, reply length=${reply.length}`);
105
+
106
+ // return { type: "reply", userId, text: reply || "[无回复]" };
107
+ return {
108
+ messageType: "openclaw_bot_chat",
109
+ _userId: msg._userId,
110
+ source: "client",
111
+ content: {
112
+ bot_token: msg.content.bot_token,
113
+ session_id: msg.content.session_id,
114
+ message_id: msg.content.message_id,
115
+ response: reply,
116
+ }
117
+ }
118
+
119
+ } catch (err) {
120
+ error(`dcgchat[${accountId}]: handle message failed: ${String(err)}`);
121
+ return { type: "reply", userId, text: `[错误] ${err instanceof Error ? err.message : String(err)}` };
122
+ }
123
+ }
package/src/channel.ts ADDED
@@ -0,0 +1,112 @@
1
+ import type { ChannelPlugin, OpenClawConfig } from "openclaw/plugin-sdk";
2
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
3
+ import type { ResolvedDcgchatAccount, DcgchatConfig } from "./types.js";
4
+
5
+ export function resolveAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedDcgchatAccount {
6
+ const id = accountId ?? DEFAULT_ACCOUNT_ID;
7
+ const raw = (cfg.channels?.["dcgchat"] as DcgchatConfig | undefined) ?? {};
8
+ return {
9
+ accountId: id,
10
+ enabled: raw.enabled !== false,
11
+ configured: Boolean(raw.wsUrl),
12
+ wsUrl: raw.wsUrl ?? "",
13
+ botToken: raw.botToken ?? "",
14
+ userId: raw.userId ?? "",
15
+ };
16
+ }
17
+
18
+ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
19
+ id: "dcgchat",
20
+ meta: {
21
+ id: "dcgchat",
22
+ label: "DCG Chat",
23
+ selectionLabel: "DCG Chat",
24
+ docsPath: "/channels/dcgchat",
25
+ docsLabel: "dcgchat",
26
+ blurb: "连接 OpenClaw 与 DCG Chat 产品",
27
+ order: 80,
28
+ },
29
+ capabilities: {
30
+ chatTypes: ["direct"],
31
+ polls: false,
32
+ threads: false,
33
+ media: false,
34
+ reactions: false,
35
+ edit: false,
36
+ reply: true,
37
+ },
38
+ reload: { configPrefixes: ["channels.dcgchat"] },
39
+ configSchema: {
40
+ schema: {
41
+ type: "object",
42
+ additionalProperties: false,
43
+ properties: {
44
+ enabled: { type: "boolean" },
45
+ wsUrl: { type: "string" },
46
+ botToken: { type: "string" },
47
+ userId: { type: "string" },
48
+ },
49
+ },
50
+ },
51
+ config: {
52
+ listAccountIds: () => [DEFAULT_ACCOUNT_ID],
53
+ resolveAccount: (cfg, accountId) => resolveAccount(cfg, accountId),
54
+ defaultAccountId: () => DEFAULT_ACCOUNT_ID,
55
+ setAccountEnabled: ({ cfg, enabled }) => ({
56
+ ...cfg,
57
+ channels: {
58
+ ...cfg.channels,
59
+ "dcgchat": {
60
+ ...(cfg.channels?.["dcgchat"] as Record<string, unknown> | undefined),
61
+ enabled,
62
+ },
63
+ },
64
+ }),
65
+ isConfigured: (account) => account.configured,
66
+ describeAccount: (account) => ({
67
+ accountId: account.accountId,
68
+ enabled: account.enabled,
69
+ configured: account.configured,
70
+ wsUrl: account.wsUrl,
71
+ botToken: account.botToken ? "***" : "",
72
+ userId: account.userId,
73
+ }),
74
+ },
75
+ messaging: {
76
+ normalizeTarget: (raw) => raw?.trim() || undefined,
77
+ targetResolver: {
78
+ looksLikeId: (raw) => Boolean(raw?.trim()),
79
+ hint: "userId",
80
+ },
81
+ },
82
+ outbound: {
83
+ deliveryMode: "direct",
84
+ textChunkLimit: 4000,
85
+ sendText: async ({ text, to, accountId }) => {
86
+ const target = to || "(implicit)";
87
+ console.log(`[dcgchat][${accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${target}: ${text?.slice(0, 100)}`);
88
+ return {
89
+ channel: "dcgchat",
90
+ messageId: `dcg-${Date.now()}`,
91
+ chatId: target,
92
+ };
93
+ },
94
+ },
95
+ gateway: {
96
+ startAccount: async (ctx) => {
97
+ const { monitorDcgchatProvider } = await import("./monitor.js");
98
+ const account = resolveAccount(ctx.cfg, ctx.accountId);
99
+ if (!account.wsUrl) {
100
+ ctx.log?.warn(`dcgchat[${account.accountId}]: wsUrl not configured, skipping`);
101
+ return;
102
+ }
103
+ // ctx.log?.info(`dcgchat[${account.accountId}]: connecting to ${account.wsUrl}`);
104
+ return monitorDcgchatProvider({
105
+ config: ctx.cfg,
106
+ runtime: ctx.runtime,
107
+ abortSignal: ctx.abortSignal,
108
+ accountId: ctx.accountId,
109
+ });
110
+ },
111
+ },
112
+ };
package/src/monitor.ts ADDED
@@ -0,0 +1,159 @@
1
+ import WebSocket from "ws";
2
+ import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk";
3
+ import { resolveAccount } from "./channel.js";
4
+ import { handleDcgchatMessage } from "./bot.js";
5
+ import type { InboundMessage, OutboundReply } from "./types.js";
6
+
7
+ export type MonitorDcgchatOpts = {
8
+ config?: ClawdbotConfig;
9
+ runtime?: RuntimeEnv;
10
+ abortSignal?: AbortSignal;
11
+ accountId?: string;
12
+ };
13
+
14
+ const RECONNECT_DELAY_MS = 3000;
15
+ const HEARTBEAT_INTERVAL_MS = 30_000;
16
+
17
+ function buildConnectUrl(wsUrl: string, botToken: string, userId: string): string {
18
+ const url = new URL(wsUrl);
19
+ if (botToken) url.searchParams.set("bot_token", botToken);
20
+ if (userId) url.searchParams.set("_userId", userId);
21
+ url.searchParams.set("_domainId", "1000");
22
+ url.searchParams.set("_appId", "100");
23
+ return url.toString();
24
+ }
25
+
26
+ export async function monitorDcgchatProvider(opts: MonitorDcgchatOpts): Promise<void> {
27
+ const { config, runtime, abortSignal, accountId } = opts;
28
+ const cfg = config ?? (runtime?.config?.() as ClawdbotConfig | undefined);
29
+ if (!cfg) {
30
+ runtime?.error?.("dcgchat: no config available");
31
+ return;
32
+ }
33
+
34
+ const account = resolveAccount(cfg, accountId ?? "default");
35
+ const log = runtime?.log ?? console.log;
36
+ const err = runtime?.error ?? console.error;
37
+
38
+ if (!account.wsUrl) {
39
+ err(`dcgchat[${account.accountId}]: wsUrl not configured`);
40
+ return;
41
+ }
42
+
43
+ let shouldReconnect = true;
44
+ let ws: WebSocket | null = null;
45
+ let heartbeatTimer: ReturnType<typeof setInterval> | null = null;
46
+
47
+ const stopHeartbeat = () => {
48
+ if (heartbeatTimer) {
49
+ clearInterval(heartbeatTimer);
50
+ heartbeatTimer = null;
51
+ }
52
+ };
53
+
54
+ const startHeartbeat = () => {
55
+ stopHeartbeat();
56
+ heartbeatTimer = setInterval(() => {
57
+ if (ws?.readyState === WebSocket.OPEN) {
58
+ const heartbeat = {
59
+ messageType: "openclaw_bot_heartbeat",
60
+ _userId: Number(account.userId) || 0,
61
+ source: "client",
62
+ content: {
63
+ bot_token: account.botToken,
64
+ status: "1",
65
+ },
66
+ };
67
+ ws.send(JSON.stringify(heartbeat));
68
+ log(`dcgchat[${account.accountId}]: heartbeat sent, ${JSON.stringify(heartbeat)}`);
69
+ }
70
+ }, HEARTBEAT_INTERVAL_MS);
71
+ };
72
+
73
+ const connect = () => {
74
+ if (!shouldReconnect) return;
75
+
76
+ const connectUrl = buildConnectUrl(account.wsUrl, account.botToken, account.userId);
77
+ log(`dcgchat[${account.accountId}]: connecting to ${connectUrl}`);
78
+ ws = new WebSocket(connectUrl);
79
+
80
+ ws.on("open", () => {
81
+ log(`dcgchat[${account.accountId}]: connected`);
82
+ startHeartbeat();
83
+ });
84
+
85
+ ws.on("message", async (data) => {
86
+ log(`dcgchat[${account.accountId}]: on message, ${data.toString()}`);
87
+ let parsed: { messageType?: string, content: string };
88
+ try {
89
+ parsed = JSON.parse(data.toString());
90
+ } catch {
91
+ err(`dcgchat[${account.accountId}]: invalid JSON received`);
92
+ return;
93
+ }
94
+
95
+ if (parsed.messageType === "openclaw_bot_heartbeat") {
96
+ log(`dcgchat[${account.accountId}]: heartbeat ack received, ${data.toString()}`);
97
+ return;
98
+ }
99
+
100
+ if (parsed.messageType !== "openclaw_bot_chat") {
101
+ log(`dcgchat[${account.accountId}]: ignoring unknown messageType: ${parsed.messageType}`);
102
+ return;
103
+ }
104
+
105
+ parsed.content = JSON.parse(parsed.content)
106
+
107
+ const msg = parsed as unknown as InboundMessage;
108
+ const reply = await handleDcgchatMessage({
109
+ cfg,
110
+ msg,
111
+ accountId: account.accountId,
112
+ runtime,
113
+ });
114
+
115
+ if (ws?.readyState === WebSocket.OPEN) {
116
+ const res = {
117
+ ...reply,
118
+ content: JSON.stringify(reply.content)
119
+ }
120
+ ws.send(JSON.stringify(res));
121
+ }
122
+ });
123
+
124
+ ws.on("close", () => {
125
+ stopHeartbeat();
126
+ log(`dcgchat[${account.accountId}]: disconnected`);
127
+ if (shouldReconnect) {
128
+ log(`dcgchat[${account.accountId}]: reconnecting in ${RECONNECT_DELAY_MS}ms...`);
129
+ setTimeout(connect, RECONNECT_DELAY_MS);
130
+ }
131
+ });
132
+
133
+ ws.on("error", (e) => {
134
+ err(`dcgchat[${account.accountId}]: WebSocket error: ${String(e)}`);
135
+ });
136
+ };
137
+
138
+ connect();
139
+
140
+ await new Promise<void>((resolve) => {
141
+ if (abortSignal?.aborted) {
142
+ shouldReconnect = false;
143
+ ws?.close();
144
+ resolve();
145
+ return;
146
+ }
147
+ abortSignal?.addEventListener(
148
+ "abort",
149
+ () => {
150
+ log(`dcgchat[${account.accountId}]: stopping`);
151
+ stopHeartbeat();
152
+ shouldReconnect = false;
153
+ ws?.close();
154
+ resolve();
155
+ },
156
+ { once: true },
157
+ );
158
+ });
159
+ }
package/src/runtime.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { PluginRuntime } from "openclaw/plugin-sdk";
2
+
3
+ let runtime: PluginRuntime | null = null;
4
+
5
+ export function setDcgchatRuntime(next: PluginRuntime) {
6
+ runtime = next;
7
+ }
8
+
9
+ export function getDcgchatRuntime(): PluginRuntime {
10
+ if (!runtime) {
11
+ throw new Error("DCG Chat runtime not initialized");
12
+ }
13
+ return runtime;
14
+ }
package/src/types.ts ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * 插件配置(channels.dcgchat 下的字段)
3
+ */
4
+ export type DcgchatConfig = {
5
+ enabled?: boolean;
6
+ /** 后端 WebSocket 地址,例如 ws://localhost:8080/openclaw/ws */
7
+ wsUrl?: string;
8
+ /** 连接认证 token */
9
+ botToken?: string;
10
+ /** 用户标识 */
11
+ userId?: string;
12
+ };
13
+
14
+ export type ResolvedDcgchatAccount = {
15
+ accountId: string;
16
+ enabled: boolean;
17
+ configured: boolean;
18
+ wsUrl: string;
19
+ botToken: string;
20
+ userId: string;
21
+ };
22
+
23
+ /**
24
+ * 下行消息:后端 → OpenClaw(用户发的消息)
25
+ */
26
+ // export type InboundMessage = {
27
+ // type: "message";
28
+ // userId: string;
29
+ // text: string;
30
+ // };
31
+ export type InboundMessage = {
32
+ messageType: string; // "openclaw_bot_chat",
33
+ _userId: number;
34
+ source: string; // 'server',
35
+ // content: string;
36
+ content: {
37
+ bot_token: string;
38
+ session_id: string;
39
+ message_id: string;
40
+ text: string;
41
+ }
42
+ }
43
+
44
+ // {"_userId":40,"content":"{\"bot_token\":\"sk_b7f8a3e1c5d24e6f8a1b3c4d5e6f7a8b\",\"session_id\":\"1\",\"message_id\":\"1\",\"text\":\"你好\"}","messageType":"openclaw_bot_chat","msgId":398599,"source":"server","title":"OPENCLAW机器人对话"}
45
+
46
+ /**
47
+ * 上行消息:OpenClaw → 后端(Agent 回复)
48
+ */
49
+ // export type OutboundReply = {
50
+ // type: "reply";
51
+ // userId: string;
52
+ // text: string;
53
+ // };
54
+
55
+ export type OutboundReply = {
56
+ messageType: string; // "openclaw_bot_chat",
57
+ _userId: number; // 100
58
+ source: string; // 'client',
59
+ // content: string;
60
+ content:{
61
+ bot_token: string; // ""
62
+ session_id: string; // ""
63
+ message_id: string; // ""
64
+ response: string; // ""
65
+ }
66
+ }