@efengx/openclaw-channel-dragon 0.5.17 → 0.5.19
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/dist/components/channel/ChannelComponent.d.ts +1 -0
- package/dist/components/channel/ChannelComponent.js +140 -1
- package/dist/components/sync/SseComponent.d.ts +1 -0
- package/dist/components/sync/SseComponent.js +1 -1
- package/dist/components/telemetry/TelemetryComponent.d.ts +11 -0
- package/dist/components/telemetry/TelemetryComponent.js +33 -0
- package/dist/index.js +3 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ export declare class ChannelComponent implements IComponent {
|
|
|
15
15
|
constructor(options: ChannelOptions, telemetry: TelemetryComponent);
|
|
16
16
|
start(): Promise<void>;
|
|
17
17
|
stop(): Promise<void>;
|
|
18
|
+
private stringifyProgressDetail;
|
|
18
19
|
deliverToOpenClaw: (content: string, sessionId?: string, modelId?: string, attachments?: any[], messageId?: string | number) => Promise<void>;
|
|
19
20
|
handleOutboundText: (ctx: any) => Promise<{
|
|
20
21
|
ok: boolean;
|
|
@@ -10,6 +10,21 @@ export class ChannelComponent {
|
|
|
10
10
|
}
|
|
11
11
|
async start() { }
|
|
12
12
|
async stop() { }
|
|
13
|
+
stringifyProgressDetail(value, maxLength = 240) {
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
const text = value.trim();
|
|
16
|
+
return text ? text.slice(0, maxLength) : undefined;
|
|
17
|
+
}
|
|
18
|
+
if (value == null)
|
|
19
|
+
return undefined;
|
|
20
|
+
try {
|
|
21
|
+
const text = JSON.stringify(value);
|
|
22
|
+
return text.length > maxLength ? `${text.slice(0, maxLength)}...` : text;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return String(value).slice(0, maxLength);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
13
28
|
deliverToOpenClaw = async (content, sessionId = 'default', modelId, attachments, messageId) => {
|
|
14
29
|
const replyMsgId = messageId ? `dragon_msg_${messageId}` : `dragon_msg_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
15
30
|
if (messageId && this.processedMessageIds.has(messageId))
|
|
@@ -32,6 +47,11 @@ export class ChannelComponent {
|
|
|
32
47
|
.catch(() => { })
|
|
33
48
|
.then(async () => {
|
|
34
49
|
logger?.info?.(`[Dragon Plugin] Sending to OpenClaw: "${content.substring(0, 50)}${content.length > 50 ? '...' : ''}" [Session: ${sessionId}]`);
|
|
50
|
+
const progress = (payload) => this.telemetry.reportProgress({
|
|
51
|
+
sessionId,
|
|
52
|
+
msgId: replyMsgId,
|
|
53
|
+
...payload,
|
|
54
|
+
});
|
|
35
55
|
await replyDispatcher({
|
|
36
56
|
ctx: {
|
|
37
57
|
Body: content,
|
|
@@ -61,7 +81,126 @@ export class ChannelComponent {
|
|
|
61
81
|
msgId: replyMsgId,
|
|
62
82
|
});
|
|
63
83
|
}
|
|
64
|
-
}
|
|
84
|
+
},
|
|
85
|
+
replyOptions: {
|
|
86
|
+
onReplyStart: async () => {
|
|
87
|
+
await progress({ kind: 'lifecycle', phase: 'start', status: 'running', title: '开始处理请求' });
|
|
88
|
+
},
|
|
89
|
+
onAssistantMessageStart: async () => {
|
|
90
|
+
await progress({ kind: 'assistant', phase: 'start', status: 'running', title: '开始生成回复' });
|
|
91
|
+
},
|
|
92
|
+
onPartialReply: async (payload) => {
|
|
93
|
+
await progress({
|
|
94
|
+
kind: 'assistant_delta',
|
|
95
|
+
phase: 'update',
|
|
96
|
+
status: 'running',
|
|
97
|
+
title: '正在生成回复',
|
|
98
|
+
detail: this.stringifyProgressDetail(payload?.delta || payload?.text),
|
|
99
|
+
data: { replace: payload?.replace === true },
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
onReasoningStream: async (payload) => {
|
|
103
|
+
await progress({
|
|
104
|
+
kind: 'reasoning',
|
|
105
|
+
phase: 'update',
|
|
106
|
+
status: 'running',
|
|
107
|
+
title: '正在推理',
|
|
108
|
+
detail: this.stringifyProgressDetail(payload?.text || payload),
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
onReasoningEnd: async () => {
|
|
112
|
+
await progress({ kind: 'reasoning', phase: 'end', status: 'completed', title: '推理完成' });
|
|
113
|
+
},
|
|
114
|
+
onToolStart: async (payload) => {
|
|
115
|
+
await progress({
|
|
116
|
+
kind: 'tool',
|
|
117
|
+
phase: payload?.phase || 'start',
|
|
118
|
+
status: 'running',
|
|
119
|
+
title: payload?.name ? `调用工具:${payload.name}` : '调用工具',
|
|
120
|
+
detail: this.stringifyProgressDetail(payload?.args),
|
|
121
|
+
data: payload,
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
onToolResult: async (payload) => {
|
|
125
|
+
await progress({
|
|
126
|
+
kind: 'tool',
|
|
127
|
+
phase: 'end',
|
|
128
|
+
status: 'completed',
|
|
129
|
+
title: '工具执行完成',
|
|
130
|
+
detail: this.stringifyProgressDetail(payload?.text || payload),
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
onItemEvent: async (payload) => {
|
|
134
|
+
await progress({
|
|
135
|
+
kind: payload?.kind || 'item',
|
|
136
|
+
phase: payload?.phase,
|
|
137
|
+
status: payload?.status,
|
|
138
|
+
title: payload?.title || payload?.name || '任务步骤更新',
|
|
139
|
+
detail: this.stringifyProgressDetail(payload?.progressText || payload?.summary || payload?.meta),
|
|
140
|
+
data: payload,
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
onPlanUpdate: async (payload) => {
|
|
144
|
+
await progress({
|
|
145
|
+
kind: 'plan',
|
|
146
|
+
phase: payload?.phase || 'update',
|
|
147
|
+
status: 'running',
|
|
148
|
+
title: payload?.title || '更新执行计划',
|
|
149
|
+
detail: this.stringifyProgressDetail(payload?.explanation || payload?.steps),
|
|
150
|
+
data: payload,
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
onApprovalEvent: async (payload) => {
|
|
154
|
+
await progress({
|
|
155
|
+
kind: 'approval',
|
|
156
|
+
phase: payload?.phase || 'update',
|
|
157
|
+
status: payload?.status || 'running',
|
|
158
|
+
title: payload?.title || '等待审批',
|
|
159
|
+
detail: this.stringifyProgressDetail(payload?.message || payload?.reason || payload?.command),
|
|
160
|
+
data: payload,
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
onCommandOutput: async (payload) => {
|
|
164
|
+
await progress({
|
|
165
|
+
kind: 'command',
|
|
166
|
+
phase: payload?.phase || 'update',
|
|
167
|
+
status: payload?.status || 'running',
|
|
168
|
+
title: payload?.title || payload?.name || '命令执行中',
|
|
169
|
+
detail: this.stringifyProgressDetail(payload?.output || payload?.cwd),
|
|
170
|
+
data: payload,
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
onPatchSummary: async (payload) => {
|
|
174
|
+
await progress({
|
|
175
|
+
kind: 'patch',
|
|
176
|
+
phase: payload?.phase || 'end',
|
|
177
|
+
status: payload?.status || 'completed',
|
|
178
|
+
title: payload?.title || '代码变更完成',
|
|
179
|
+
detail: this.stringifyProgressDetail(payload?.summary || {
|
|
180
|
+
added: payload?.added,
|
|
181
|
+
modified: payload?.modified,
|
|
182
|
+
deleted: payload?.deleted,
|
|
183
|
+
}),
|
|
184
|
+
data: payload,
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
onCompactionStart: async () => {
|
|
188
|
+
await progress({ kind: 'compaction', phase: 'start', status: 'running', title: '正在压缩上下文' });
|
|
189
|
+
},
|
|
190
|
+
onCompactionEnd: async () => {
|
|
191
|
+
await progress({ kind: 'compaction', phase: 'end', status: 'completed', title: '上下文压缩完成' });
|
|
192
|
+
},
|
|
193
|
+
onModelSelected: (model) => {
|
|
194
|
+
void progress({
|
|
195
|
+
kind: 'model',
|
|
196
|
+
phase: 'selected',
|
|
197
|
+
status: 'completed',
|
|
198
|
+
title: '已选择模型',
|
|
199
|
+
detail: [model?.provider, model?.model].filter(Boolean).join('/'),
|
|
200
|
+
data: model,
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
},
|
|
65
204
|
});
|
|
66
205
|
})
|
|
67
206
|
.finally(() => {
|
|
@@ -24,7 +24,7 @@ export class SseComponent {
|
|
|
24
24
|
return;
|
|
25
25
|
const { agentId, logger } = this.options;
|
|
26
26
|
const url = `${this.http.options.baseURL}/api/agents/events`;
|
|
27
|
-
logger?.info?.(`[Dragon Plugin]
|
|
27
|
+
logger?.info?.(`[Dragon Plugin] v${this.options.version} connecting to Orchestrator SSE: ${url} (agent=${agentId})`);
|
|
28
28
|
try {
|
|
29
29
|
// In Node 22, we might need a fetch-based SSE or a library,
|
|
30
30
|
// but for simplicity we'll use the same pattern as Bridge if possible.
|
|
@@ -7,6 +7,7 @@ export declare class TelemetryComponent implements IComponent {
|
|
|
7
7
|
start(): Promise<void>;
|
|
8
8
|
stop(): Promise<void>;
|
|
9
9
|
private lastReplies;
|
|
10
|
+
private lastProgress;
|
|
10
11
|
reportReply(payload: {
|
|
11
12
|
content: string;
|
|
12
13
|
sessionId: string;
|
|
@@ -16,4 +17,14 @@ export declare class TelemetryComponent implements IComponent {
|
|
|
16
17
|
msgId?: string;
|
|
17
18
|
}): Promise<void>;
|
|
18
19
|
reportEvent(stream: string, data: any, ts: number): Promise<void>;
|
|
20
|
+
reportProgress(payload: {
|
|
21
|
+
sessionId: string;
|
|
22
|
+
msgId?: string;
|
|
23
|
+
kind: string;
|
|
24
|
+
phase?: string;
|
|
25
|
+
status?: string;
|
|
26
|
+
title?: string;
|
|
27
|
+
detail?: string;
|
|
28
|
+
data?: any;
|
|
29
|
+
}): Promise<void>;
|
|
19
30
|
}
|
|
@@ -8,6 +8,7 @@ export class TelemetryComponent {
|
|
|
8
8
|
async start() { }
|
|
9
9
|
async stop() { }
|
|
10
10
|
lastReplies = new Map();
|
|
11
|
+
lastProgress = new Map();
|
|
11
12
|
async reportReply(payload) {
|
|
12
13
|
try {
|
|
13
14
|
const source = payload.source || "unknown";
|
|
@@ -69,4 +70,36 @@ export class TelemetryComponent {
|
|
|
69
70
|
catch (e) {
|
|
70
71
|
}
|
|
71
72
|
}
|
|
73
|
+
async reportProgress(payload) {
|
|
74
|
+
try {
|
|
75
|
+
const sessionId = payload.sessionId || "default";
|
|
76
|
+
const key = `${sessionId}:${payload.kind}:${payload.title || ""}`;
|
|
77
|
+
const signature = JSON.stringify({
|
|
78
|
+
phase: payload.phase,
|
|
79
|
+
status: payload.status,
|
|
80
|
+
detail: payload.detail,
|
|
81
|
+
data: payload.data,
|
|
82
|
+
});
|
|
83
|
+
const now = Date.now();
|
|
84
|
+
const last = this.lastProgress.get(key);
|
|
85
|
+
if (last && last.signature === signature && now - last.timestamp < 1000) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if ((payload.kind === "assistant_delta" || payload.kind === "reasoning") && last && now - last.timestamp < 350) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
this.lastProgress.set(key, { signature, timestamp: now });
|
|
92
|
+
await this.http.fetch(`/api/agents/${this.agentId}/messages/progress`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: { "Content-Type": "application/json" },
|
|
95
|
+
body: JSON.stringify({
|
|
96
|
+
...payload,
|
|
97
|
+
sessionId,
|
|
98
|
+
ts: now,
|
|
99
|
+
}),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
}
|
|
104
|
+
}
|
|
72
105
|
}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { TelemetryComponent } from "./components/telemetry/TelemetryComponent.js
|
|
|
6
6
|
import { HttpComponent } from "./components/http/HttpComponent.js";
|
|
7
7
|
import { ChannelComponent } from "./components/channel/ChannelComponent.js";
|
|
8
8
|
import { SseComponent } from "./components/sync/SseComponent.js";
|
|
9
|
+
import { dragonChannelPluginVersion } from "./version.js";
|
|
9
10
|
const channelId = "dragon";
|
|
10
11
|
let cachedRuntime;
|
|
11
12
|
const containers = new Map();
|
|
@@ -15,6 +16,7 @@ async function getOrCreateContainer(account, ctx) {
|
|
|
15
16
|
return containers.get(key);
|
|
16
17
|
const logger = ctx?.logger ?? ctx?.log ?? cachedRuntime?.logger ?? cachedRuntime?.log;
|
|
17
18
|
const container = new ServiceContainer();
|
|
19
|
+
logger?.info?.(`[Dragon Plugin] Starting channel plugin v${dragonChannelPluginVersion} for agent=${account.agentId}, account=${account.accountId}, orchestrator=${account.orchestratorUrl}`);
|
|
18
20
|
// 1. Core Infrastructure
|
|
19
21
|
const http = container.register('http', new HttpComponent({
|
|
20
22
|
baseURL: account.orchestratorUrl,
|
|
@@ -33,6 +35,7 @@ async function getOrCreateContainer(account, ctx) {
|
|
|
33
35
|
// 3. Sync Infrastructure
|
|
34
36
|
container.register('sse', new SseComponent(http, channel, {
|
|
35
37
|
agentId: account.agentId,
|
|
38
|
+
version: dragonChannelPluginVersion,
|
|
36
39
|
logger
|
|
37
40
|
}));
|
|
38
41
|
await container.startAll();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const dragonChannelPluginVersion = "0.5.19";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const dragonChannelPluginVersion = "0.5.19";
|
package/openclaw.plugin.json
CHANGED