@efengx/openclaw-channel-dragon 0.4.0 → 0.4.4
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 +25 -0
- package/dist/components/channel/ChannelComponent.js +99 -0
- package/dist/components/http/HttpComponent.d.ts +13 -0
- package/dist/components/http/HttpComponent.js +27 -0
- package/dist/components/sync/PollingComponent.d.ts +5 -3
- package/dist/components/sync/PollingComponent.js +13 -12
- package/dist/components/telemetry/TelemetryComponent.d.ts +4 -6
- package/dist/components/telemetry/TelemetryComponent.js +9 -12
- package/dist/index.js +28 -92
- package/package.json +1 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IComponent } from "../../core/IComponent.js";
|
|
2
|
+
import { BridgeComponent } from "../bridge/BridgeComponent.js";
|
|
3
|
+
import { TelemetryComponent } from "../telemetry/TelemetryComponent.js";
|
|
4
|
+
export interface ChannelOptions {
|
|
5
|
+
accountId: string;
|
|
6
|
+
agentId: string;
|
|
7
|
+
channelRuntime: any;
|
|
8
|
+
cfg: any;
|
|
9
|
+
logger?: any;
|
|
10
|
+
}
|
|
11
|
+
export declare class ChannelComponent implements IComponent {
|
|
12
|
+
private options;
|
|
13
|
+
private bridge;
|
|
14
|
+
private telemetry;
|
|
15
|
+
private processedMessageIds;
|
|
16
|
+
constructor(options: ChannelOptions, bridge: BridgeComponent, telemetry: TelemetryComponent);
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
stop(): Promise<void>;
|
|
19
|
+
deliverToOpenClaw: (content: string, sessionId?: string, modelId?: string, attachments?: any[], messageId?: string | number) => Promise<void>;
|
|
20
|
+
handleOutboundText: (ctx: any) => Promise<{
|
|
21
|
+
ok: boolean;
|
|
22
|
+
messageId: string;
|
|
23
|
+
}>;
|
|
24
|
+
handleAgentEvent: (evt: any) => Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const channelId = "dragon";
|
|
2
|
+
export class ChannelComponent {
|
|
3
|
+
options;
|
|
4
|
+
bridge;
|
|
5
|
+
telemetry;
|
|
6
|
+
processedMessageIds = new Set();
|
|
7
|
+
constructor(options, bridge, telemetry) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
this.bridge = bridge;
|
|
10
|
+
this.telemetry = telemetry;
|
|
11
|
+
}
|
|
12
|
+
async start() { }
|
|
13
|
+
async stop() { }
|
|
14
|
+
deliverToOpenClaw = async (content, sessionId = 'default', modelId, attachments, messageId) => {
|
|
15
|
+
if (messageId && this.processedMessageIds.has(messageId))
|
|
16
|
+
return;
|
|
17
|
+
if (messageId) {
|
|
18
|
+
this.processedMessageIds.add(messageId);
|
|
19
|
+
if (this.processedMessageIds.size > 1000) {
|
|
20
|
+
const first = this.processedMessageIds.values().next().value;
|
|
21
|
+
if (first !== undefined)
|
|
22
|
+
this.processedMessageIds.delete(first);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const replyDispatcher = this.options.channelRuntime?.reply?.dispatchReplyWithBufferedBlockDispatcher;
|
|
26
|
+
if (typeof replyDispatcher !== 'function')
|
|
27
|
+
return;
|
|
28
|
+
const { accountId, agentId, cfg, logger } = this.options;
|
|
29
|
+
const sessionKey = `dragon:${agentId}:direct:${sessionId}`;
|
|
30
|
+
await replyDispatcher({
|
|
31
|
+
ctx: {
|
|
32
|
+
Body: content,
|
|
33
|
+
From: sessionId === 'default' ? "workbench-user" : `workbench-user-${sessionId}`,
|
|
34
|
+
To: agentId,
|
|
35
|
+
ChatType: "direct",
|
|
36
|
+
Provider: channelId,
|
|
37
|
+
ChannelId: channelId,
|
|
38
|
+
AccountId: accountId,
|
|
39
|
+
SessionKey: sessionKey,
|
|
40
|
+
Timestamp: Date.now(),
|
|
41
|
+
Model: modelId,
|
|
42
|
+
Attachments: attachments,
|
|
43
|
+
},
|
|
44
|
+
cfg,
|
|
45
|
+
dispatcherOptions: {
|
|
46
|
+
deliver: async (payload) => {
|
|
47
|
+
const text = payload?.text || "";
|
|
48
|
+
if (!text && !payload?.tool_calls?.length)
|
|
49
|
+
return;
|
|
50
|
+
if (this.bridge.client) {
|
|
51
|
+
this.bridge.client.sendJson({
|
|
52
|
+
type: "outbound_text",
|
|
53
|
+
channel: channelId,
|
|
54
|
+
text,
|
|
55
|
+
tool_calls: payload?.tool_calls,
|
|
56
|
+
reasoning_content: payload?.reasoning_content,
|
|
57
|
+
route: { agentId, accountId, peer: { kind: "direct", id: sessionId }, sessionKey },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
await this.telemetry.reportReply({
|
|
61
|
+
content: text,
|
|
62
|
+
sessionId,
|
|
63
|
+
tool_calls: payload?.tool_calls,
|
|
64
|
+
reasoning_content: payload?.reasoning_content,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
handleOutboundText = async (ctx) => {
|
|
71
|
+
const text = ctx?.text || "";
|
|
72
|
+
const { accountId, agentId } = this.options;
|
|
73
|
+
if (this.bridge.client) {
|
|
74
|
+
this.bridge.client.sendJson({
|
|
75
|
+
type: "outbound_text",
|
|
76
|
+
channel: channelId,
|
|
77
|
+
text,
|
|
78
|
+
route: { agentId, accountId, peer: ctx?.peer, sessionKey: ctx?.ctx?.SessionKey },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
await this.telemetry.reportReply({ content: text, sessionId: ctx?.peer?.id || 'default' });
|
|
82
|
+
return { ok: true, messageId: Date.now().toString() };
|
|
83
|
+
};
|
|
84
|
+
handleAgentEvent = async (evt) => {
|
|
85
|
+
const { agentId, accountId } = this.options;
|
|
86
|
+
if (this.bridge.client) {
|
|
87
|
+
this.bridge.client.sendJson({
|
|
88
|
+
type: "agent_event",
|
|
89
|
+
channel: channelId,
|
|
90
|
+
agentId,
|
|
91
|
+
runId: evt.runId,
|
|
92
|
+
stream: evt.stream,
|
|
93
|
+
data: evt.data,
|
|
94
|
+
sessionKey: evt.sessionKey
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
await this.telemetry.reportEvent(evt.stream, evt.data, evt.ts);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IComponent } from "../../core/IComponent.js";
|
|
2
|
+
export interface HttpOptions {
|
|
3
|
+
baseURL: string;
|
|
4
|
+
authToken?: string;
|
|
5
|
+
logger?: any;
|
|
6
|
+
}
|
|
7
|
+
export declare class HttpComponent implements IComponent {
|
|
8
|
+
private options;
|
|
9
|
+
constructor(options: HttpOptions);
|
|
10
|
+
start(): Promise<void>;
|
|
11
|
+
stop(): Promise<void>;
|
|
12
|
+
fetch(path: string, init?: RequestInit): Promise<Response>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class HttpComponent {
|
|
2
|
+
options;
|
|
3
|
+
constructor(options) {
|
|
4
|
+
this.options = options;
|
|
5
|
+
}
|
|
6
|
+
async start() {
|
|
7
|
+
this.options.logger?.info?.(`[Dragon-Channel] HttpComponent started for ${this.options.baseURL}`);
|
|
8
|
+
}
|
|
9
|
+
async stop() { }
|
|
10
|
+
async fetch(path, init) {
|
|
11
|
+
const url = `${this.options.baseURL}${path}`;
|
|
12
|
+
const headers = {
|
|
13
|
+
...(init?.headers || {}),
|
|
14
|
+
};
|
|
15
|
+
if (this.options.authToken) {
|
|
16
|
+
headers['Authorization'] = `Bearer ${this.options.authToken}`;
|
|
17
|
+
}
|
|
18
|
+
const res = await fetch(url, {
|
|
19
|
+
...init,
|
|
20
|
+
headers
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok && res.status !== 404) {
|
|
23
|
+
this.options.logger?.warn?.(`[Dragon-Channel] HTTP Request failed: ${res.status} ${url}`);
|
|
24
|
+
}
|
|
25
|
+
return res;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { IComponent } from "../../core/IComponent.js";
|
|
2
|
+
import { HttpComponent } from "../http/HttpComponent.js";
|
|
3
|
+
import { ChannelComponent } from "../channel/ChannelComponent.js";
|
|
2
4
|
export declare class PollingComponent implements IComponent {
|
|
5
|
+
private http;
|
|
6
|
+
private channel;
|
|
3
7
|
private options;
|
|
4
8
|
private pollInterval;
|
|
5
|
-
constructor(options: {
|
|
9
|
+
constructor(http: HttpComponent, channel: ChannelComponent, options: {
|
|
6
10
|
agentId: string;
|
|
7
|
-
orchestratorUrl: string;
|
|
8
11
|
accountId: string;
|
|
9
12
|
abortSignal: AbortSignal;
|
|
10
13
|
logger?: any;
|
|
11
|
-
deliverToOpenClaw: (content: string, sessionId?: string, modelId?: string, attachments?: any[], messageId?: string | number) => Promise<void>;
|
|
12
14
|
});
|
|
13
15
|
start(): Promise<void>;
|
|
14
16
|
stop(): Promise<void>;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import * as http2 from "node:http2";
|
|
2
2
|
export class PollingComponent {
|
|
3
|
+
http;
|
|
4
|
+
channel;
|
|
3
5
|
options;
|
|
4
6
|
pollInterval = null;
|
|
5
|
-
constructor(options) {
|
|
7
|
+
constructor(http, channel, options) {
|
|
8
|
+
this.http = http;
|
|
9
|
+
this.channel = channel;
|
|
6
10
|
this.options = options;
|
|
7
11
|
}
|
|
8
12
|
async start() {
|
|
@@ -19,17 +23,16 @@ export class PollingComponent {
|
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
25
|
async consumePendingMessages() {
|
|
22
|
-
const { agentId,
|
|
26
|
+
const { agentId, logger } = this.options;
|
|
23
27
|
try {
|
|
24
|
-
const
|
|
25
|
-
const res = await fetch(pollUrl);
|
|
28
|
+
const res = await this.http.fetch(`/api/agents/${agentId}/messages/poll`);
|
|
26
29
|
if (res.ok) {
|
|
27
30
|
const data = (await res.json());
|
|
28
31
|
const messages = data.messages || [];
|
|
29
32
|
if (messages.length > 0) {
|
|
30
33
|
logger?.info?.(`dragon channel: [RECOVERY] Consuming ${messages.length} pending messages via polling.`);
|
|
31
34
|
for (const m of messages) {
|
|
32
|
-
await deliverToOpenClaw(String(m.content || ''), String(m.sessionId || 'default'), m.modelId, m.attachments, m.id);
|
|
35
|
+
await this.channel.deliverToOpenClaw(String(m.content || ''), String(m.sessionId || 'default'), m.modelId, m.attachments, m.id);
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
}
|
|
@@ -39,7 +42,7 @@ export class PollingComponent {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
async startLoop() {
|
|
42
|
-
const {
|
|
45
|
+
const { logger, abortSignal } = this.options;
|
|
43
46
|
let attempt = 0;
|
|
44
47
|
while (!abortSignal.aborted) {
|
|
45
48
|
try {
|
|
@@ -57,8 +60,8 @@ export class PollingComponent {
|
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
async connectOnce() {
|
|
60
|
-
const { agentId,
|
|
61
|
-
const
|
|
63
|
+
const { agentId, logger, abortSignal } = this.options;
|
|
64
|
+
const ssePath = `/api/agents/events`;
|
|
62
65
|
void this.consumePendingMessages();
|
|
63
66
|
const handleSseText = async (chunkText, bufRef) => {
|
|
64
67
|
bufRef.buf += chunkText;
|
|
@@ -78,19 +81,17 @@ export class PollingComponent {
|
|
|
78
81
|
try {
|
|
79
82
|
const evt = JSON.parse(dataStr);
|
|
80
83
|
if (evt?.type === 'WORKBENCH_MESSAGE' && evt.agentId === agentId) {
|
|
81
|
-
await deliverToOpenClaw(String(evt?.payload?.content || ''), String(evt?.payload?.sessionId || 'default'), evt?.payload?.modelId, evt?.payload?.attachments, evt?.payload?.id);
|
|
84
|
+
await this.channel.deliverToOpenClaw(String(evt?.payload?.content || ''), String(evt?.payload?.sessionId || 'default'), evt?.payload?.modelId, evt?.payload?.attachments, evt?.payload?.id);
|
|
82
85
|
}
|
|
83
86
|
}
|
|
84
87
|
catch (e) { }
|
|
85
88
|
}
|
|
86
89
|
};
|
|
87
|
-
const res = await fetch(
|
|
90
|
+
const res = await this.http.fetch(ssePath, {
|
|
88
91
|
signal: abortSignal,
|
|
89
92
|
headers: { Accept: 'text/event-stream' },
|
|
90
93
|
});
|
|
91
94
|
if (res.status === 404) {
|
|
92
|
-
// HTTP/2 fallback logic (simplified for brevity here, original has full impl)
|
|
93
|
-
await this.connectHttp2(sseUrl, handleSseText);
|
|
94
95
|
return;
|
|
95
96
|
}
|
|
96
97
|
if (!res.ok)
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { IComponent } from "../../core/IComponent.js";
|
|
2
|
+
import { HttpComponent } from "../http/HttpComponent.js";
|
|
2
3
|
export declare class TelemetryComponent implements IComponent {
|
|
3
|
-
private
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
orchestratorUrl: string;
|
|
7
|
-
logger?: any;
|
|
8
|
-
});
|
|
4
|
+
private http;
|
|
5
|
+
private agentId;
|
|
6
|
+
constructor(http: HttpComponent, agentId: string);
|
|
9
7
|
start(): Promise<void>;
|
|
10
8
|
stop(): Promise<void>;
|
|
11
9
|
reportReply(payload: {
|
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
export class TelemetryComponent {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
http;
|
|
3
|
+
agentId;
|
|
4
|
+
constructor(http, agentId) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
this.agentId = agentId;
|
|
5
7
|
}
|
|
6
8
|
async start() { }
|
|
7
9
|
async stop() { }
|
|
8
10
|
async reportReply(payload) {
|
|
9
|
-
const { agentId, orchestratorUrl, logger } = this.options;
|
|
10
11
|
try {
|
|
11
|
-
|
|
12
|
-
await fetch(replyUrl, {
|
|
12
|
+
await this.http.fetch(`/api/agents/${this.agentId}/messages/reply`, {
|
|
13
13
|
method: "POST",
|
|
14
14
|
headers: { "Content-Type": "application/json" },
|
|
15
15
|
body: JSON.stringify(payload),
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
catch (e) {
|
|
19
|
-
|
|
19
|
+
// Error logged by HttpComponent
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
async reportEvent(stream, data, ts) {
|
|
23
|
-
const { agentId, orchestratorUrl, logger } = this.options;
|
|
24
23
|
try {
|
|
25
|
-
const telemetryUrl = `${orchestratorUrl}/api/agents/${agentId}/messages/reply`;
|
|
26
24
|
let telemetryPayload = null;
|
|
27
25
|
if (stream === "thinking") {
|
|
28
26
|
telemetryPayload = { content: "", ts, metadata: { isTelemetry: true, reasoning_content: data, stream: "thinking" } };
|
|
@@ -43,15 +41,14 @@ export class TelemetryComponent {
|
|
|
43
41
|
};
|
|
44
42
|
}
|
|
45
43
|
if (telemetryPayload) {
|
|
46
|
-
|
|
44
|
+
this.http.fetch(`/api/agents/${this.agentId}/messages/reply`, {
|
|
47
45
|
method: "POST",
|
|
48
46
|
headers: { "Content-Type": "application/json" },
|
|
49
47
|
body: JSON.stringify(telemetryPayload),
|
|
50
|
-
}).catch(
|
|
48
|
+
}).catch(() => { });
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
51
|
catch (e) {
|
|
54
|
-
logger?.error?.(`[Dragon] Telemetry resolution failed: ${e.message}`);
|
|
55
52
|
}
|
|
56
53
|
}
|
|
57
54
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,16 +5,24 @@ import { ServiceContainer } from "./core/ServiceContainer.js";
|
|
|
5
5
|
import { BridgeComponent } from "./components/bridge/BridgeComponent.js";
|
|
6
6
|
import { PollingComponent } from "./components/sync/PollingComponent.js";
|
|
7
7
|
import { TelemetryComponent } from "./components/telemetry/TelemetryComponent.js";
|
|
8
|
+
import { HttpComponent } from "./components/http/HttpComponent.js";
|
|
9
|
+
import { ChannelComponent } from "./components/channel/ChannelComponent.js";
|
|
8
10
|
const channelId = "dragon";
|
|
9
11
|
let cachedRuntime;
|
|
10
12
|
const containers = new Map();
|
|
11
|
-
const processedMessageIds = new Set();
|
|
12
13
|
async function getOrCreateContainer(account, ctx) {
|
|
13
14
|
const key = `${account.agentId}:${account.orchestratorUrl}`;
|
|
14
15
|
if (containers.has(key))
|
|
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
|
+
// 1. Core Infrastructure
|
|
20
|
+
const http = container.register('http', new HttpComponent({
|
|
21
|
+
baseURL: account.orchestratorUrl,
|
|
22
|
+
authToken: account.orchestratorAuthToken || process.env.DRAGON_ORCHESTRATOR_AUTH_TOKEN || process.env.DRAGON_GATEWAY_TOKEN,
|
|
23
|
+
logger
|
|
24
|
+
}));
|
|
25
|
+
const telemetry = container.register('telemetry', new TelemetryComponent(http, account.agentId));
|
|
18
26
|
const bridge = container.register('bridge', new BridgeComponent({
|
|
19
27
|
port: parseInt(account.bridgePort || "18799", 10),
|
|
20
28
|
token: account.bridgeToken || "",
|
|
@@ -23,73 +31,20 @@ async function getOrCreateContainer(account, ctx) {
|
|
|
23
31
|
gatewayToken: account.gatewayToken || "",
|
|
24
32
|
logger
|
|
25
33
|
}));
|
|
26
|
-
|
|
34
|
+
// 2. Channel Logic (Centralized)
|
|
35
|
+
const channel = container.register('channel', new ChannelComponent({
|
|
36
|
+
accountId: account.accountId,
|
|
27
37
|
agentId: account.agentId,
|
|
28
|
-
|
|
38
|
+
channelRuntime: ctx.channelRuntime,
|
|
39
|
+
cfg: ctx.cfg,
|
|
29
40
|
logger
|
|
30
|
-
}));
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return;
|
|
34
|
-
if (messageId) {
|
|
35
|
-
processedMessageIds.add(messageId);
|
|
36
|
-
if (processedMessageIds.size > 1000) {
|
|
37
|
-
const first = processedMessageIds.values().next().value;
|
|
38
|
-
if (first !== undefined)
|
|
39
|
-
processedMessageIds.delete(first);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const replyDispatcher = ctx.channelRuntime?.reply?.dispatchReplyWithBufferedBlockDispatcher;
|
|
43
|
-
if (typeof replyDispatcher !== 'function')
|
|
44
|
-
return;
|
|
45
|
-
const sessionKey = `dragon:${account.agentId}:direct:${sessionId}`;
|
|
46
|
-
await replyDispatcher({
|
|
47
|
-
ctx: {
|
|
48
|
-
Body: content,
|
|
49
|
-
From: sessionId === 'default' ? "workbench-user" : `workbench-user-${sessionId}`,
|
|
50
|
-
To: account.agentId,
|
|
51
|
-
ChatType: "direct",
|
|
52
|
-
Provider: channelId,
|
|
53
|
-
ChannelId: channelId,
|
|
54
|
-
AccountId: account.accountId,
|
|
55
|
-
SessionKey: sessionKey,
|
|
56
|
-
Timestamp: Date.now(),
|
|
57
|
-
Model: modelId,
|
|
58
|
-
Attachments: attachments,
|
|
59
|
-
},
|
|
60
|
-
cfg: ctx.cfg,
|
|
61
|
-
dispatcherOptions: {
|
|
62
|
-
deliver: async (payload) => {
|
|
63
|
-
const text = payload?.text || "";
|
|
64
|
-
if (!text && !payload?.tool_calls?.length)
|
|
65
|
-
return;
|
|
66
|
-
if (bridge.client) {
|
|
67
|
-
bridge.client.sendJson({
|
|
68
|
-
type: "outbound_text",
|
|
69
|
-
channel: channelId,
|
|
70
|
-
text,
|
|
71
|
-
tool_calls: payload?.tool_calls,
|
|
72
|
-
reasoning_content: payload?.reasoning_content,
|
|
73
|
-
route: { agentId: account.agentId, accountId: account.accountId, peer: { kind: "direct", id: sessionId }, sessionKey },
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
await telemetry.reportReply({
|
|
77
|
-
content: text,
|
|
78
|
-
sessionId,
|
|
79
|
-
tool_calls: payload?.tool_calls,
|
|
80
|
-
reasoning_content: payload?.reasoning_content,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
container.register('polling', new PollingComponent({
|
|
41
|
+
}, bridge, telemetry));
|
|
42
|
+
// 3. Polling Infrastructure
|
|
43
|
+
container.register('polling', new PollingComponent(http, channel, {
|
|
87
44
|
agentId: account.agentId,
|
|
88
|
-
orchestratorUrl: account.orchestratorUrl,
|
|
89
45
|
accountId: account.accountId,
|
|
90
46
|
abortSignal: ctx.abortSignal,
|
|
91
|
-
logger
|
|
92
|
-
deliverToOpenClaw
|
|
47
|
+
logger
|
|
93
48
|
}));
|
|
94
49
|
await container.startAll();
|
|
95
50
|
containers.set(key, container);
|
|
@@ -110,6 +65,7 @@ const base = createChannelPluginBase({
|
|
|
110
65
|
accountId,
|
|
111
66
|
agentId: accountConfig.agentId || accountId,
|
|
112
67
|
orchestratorUrl: accountConfig.orchestratorUrl || "http://127.0.0.1:4000",
|
|
68
|
+
orchestratorAuthToken: accountConfig.orchestratorAuthToken || accountConfig.authToken,
|
|
113
69
|
bridgePort: accountConfig.bridgePort,
|
|
114
70
|
bridgeToken: accountConfig.bridgeToken,
|
|
115
71
|
gatewayPort: accountConfig.gatewayPort,
|
|
@@ -133,21 +89,10 @@ const plugin = createChatChannelPlugin({
|
|
|
133
89
|
attachedResults: createRawChannelSendResultAdapter({
|
|
134
90
|
channel: channelId,
|
|
135
91
|
async sendText(ctx) {
|
|
136
|
-
const text = ctx?.text || "";
|
|
137
92
|
const account = base.config.resolveAccount(ctx.cfg, ctx.accountId);
|
|
138
93
|
const container = await getOrCreateContainer(account, ctx);
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
if (bridge.client) {
|
|
142
|
-
bridge.client.sendJson({
|
|
143
|
-
type: "outbound_text",
|
|
144
|
-
channel: channelId,
|
|
145
|
-
text,
|
|
146
|
-
route: { agentId: account.agentId, accountId: account.accountId, peer: ctx?.peer, sessionKey: ctx?.ctx?.SessionKey },
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
await telemetry.reportReply({ content: text, sessionId: ctx?.peer?.id || 'default' });
|
|
150
|
-
return { ok: true, messageId: Date.now().toString() };
|
|
94
|
+
const channel = container.get('channel');
|
|
95
|
+
return await channel.handleOutboundText(ctx);
|
|
151
96
|
},
|
|
152
97
|
}),
|
|
153
98
|
},
|
|
@@ -165,24 +110,15 @@ const entry = defineChannelPluginEntry({
|
|
|
165
110
|
const sessionKey = evt.sessionKey;
|
|
166
111
|
if (!sessionKey || !sessionKey.startsWith(`${channelId}:`))
|
|
167
112
|
return;
|
|
168
|
-
const agentId = sessionKey.split(':')[1] || "";
|
|
169
113
|
const accountId = sessionKey.split(':')[2] || "default";
|
|
170
114
|
const account = base.config.resolveAccount(api.runtime.cfg, accountId);
|
|
171
|
-
const container = await getOrCreateContainer(account, {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
agentId,
|
|
179
|
-
runId: evt.runId,
|
|
180
|
-
stream: evt.stream,
|
|
181
|
-
data: evt.data,
|
|
182
|
-
sessionKey
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
await telemetry.reportEvent(evt.stream, evt.data, evt.ts);
|
|
115
|
+
const container = await getOrCreateContainer(account, {
|
|
116
|
+
cfg: api.runtime.cfg,
|
|
117
|
+
abortSignal: new AbortController().signal,
|
|
118
|
+
channelRuntime: api.runtime.channelRuntime // Ensure runtime is passed
|
|
119
|
+
});
|
|
120
|
+
const channel = container.get('channel');
|
|
121
|
+
await channel.handleAgentEvent(evt);
|
|
186
122
|
});
|
|
187
123
|
}
|
|
188
124
|
}
|