@anwenhappy2026/x-channel 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 +183 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/setup-entry.d.ts +5 -0
- package/dist/setup-entry.d.ts.map +1 -0
- package/dist/setup-entry.js +4 -0
- package/dist/setup-entry.js.map +1 -0
- package/dist/src/channel.d.ts +22 -0
- package/dist/src/channel.d.ts.map +1 -0
- package/dist/src/channel.js +156 -0
- package/dist/src/channel.js.map +1 -0
- package/dist/src/gateway.d.ts +17 -0
- package/dist/src/gateway.d.ts.map +1 -0
- package/dist/src/gateway.js +314 -0
- package/dist/src/gateway.js.map +1 -0
- package/dist/src/http-handler.d.ts +4 -0
- package/dist/src/http-handler.d.ts.map +1 -0
- package/dist/src/http-handler.js +443 -0
- package/dist/src/http-handler.js.map +1 -0
- package/dist/src/runtime.d.ts +4 -0
- package/dist/src/runtime.d.ts.map +1 -0
- package/dist/src/runtime.js +11 -0
- package/dist/src/runtime.js.map +1 -0
- package/openclaw.plugin.json +90 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# x-channel
|
|
2
|
+
|
|
3
|
+
`x-channel` provides a lightweight inbound bridge into OpenClaw so you can push test messages via HTTP or allow your own WebSocket server to dispatch inbound events. It is built on the OpenClaw channel runtime and reuses the same dispatch/streaming flow as the core platform.
|
|
4
|
+
|
|
5
|
+
## Auto install + first-start bootstrap
|
|
6
|
+
|
|
7
|
+
If you want OpenClaw to install and configure this plugin automatically on first startup, use the bootstrap scripts in `/scripts`:
|
|
8
|
+
|
|
9
|
+
1) Build a local package tarball (optional, for offline/local install):
|
|
10
|
+
|
|
11
|
+
```powershell
|
|
12
|
+
cd extensions/x-channel
|
|
13
|
+
npm pack
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This creates a file like `xclaw-x-channel-0.1.0.tgz`.
|
|
17
|
+
|
|
18
|
+
2) Start OpenClaw through the wrapper script:
|
|
19
|
+
|
|
20
|
+
```powershell
|
|
21
|
+
cd ../..
|
|
22
|
+
./scripts/start-openclaw-with-x-channel.ps1
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
To install from a local tarball instead of npm:
|
|
26
|
+
|
|
27
|
+
```powershell
|
|
28
|
+
./scripts/start-openclaw-with-x-channel.ps1 -PluginSpec ".\extensions\x-channel\xclaw-x-channel-0.1.0.tgz"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
What happens on first run:
|
|
32
|
+
|
|
33
|
+
- Runs `openclaw plugins install <PluginSpec>`
|
|
34
|
+
- Creates/merges `~/.openclaw/openclaw.json`
|
|
35
|
+
- Adds default `channels.x-channel` and `agents.defaults` values if missing
|
|
36
|
+
- Writes a one-time marker file `~/.openclaw/.x-channel-bootstrap.done`
|
|
37
|
+
|
|
38
|
+
Subsequent runs skip bootstrap unless you delete the marker file.
|
|
39
|
+
|
|
40
|
+
## Implementation outline
|
|
41
|
+
|
|
42
|
+
1. The plugin registers a channel with the identifier `x-channel` and an HTTP route on the OpenClaw server.
|
|
43
|
+
2. When the gateway starts an account, it instantiates:
|
|
44
|
+
- An HTTP route registered at `/v1/chat/completions` on the OpenClaw server (no separate port needed).
|
|
45
|
+
- An optional outgoing WS client that connects to your server, handles reconnect/backoff, and forwards WS payloads into OpenClaw.
|
|
46
|
+
3. Both HTTP and WS inputs run through the shared channel routing stack:
|
|
47
|
+
- `runtime.channel.routing.resolveAgentRoute(...)`
|
|
48
|
+
- `runtime.channel.reply.finalizeInboundContext(...)`
|
|
49
|
+
- `runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher(...)`
|
|
50
|
+
4. WS replies use the streaming protocol defined below (accepted → zero/more delta → done). The last `delta` emitted by the dispatcher carries `done: true`. If no incremental blocks are produced, the connector falls back to the `done` frame.
|
|
51
|
+
|
|
52
|
+
## Configuration
|
|
53
|
+
|
|
54
|
+
Add or merge the following into your OpenClaw config (typically `~/.openclaw/openclaw.json`):
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"channels": {
|
|
59
|
+
"x-channel": {
|
|
60
|
+
"defaultAccountId": "default",
|
|
61
|
+
"defaultConversationId": "server-tests",
|
|
62
|
+
"ws": {
|
|
63
|
+
"enabled": true,
|
|
64
|
+
"url": "ws://127.0.0.1:9001/openclaw",
|
|
65
|
+
"protocols": [],
|
|
66
|
+
"initialRetryMs": 1000,
|
|
67
|
+
"maxRetryMs": 30000,
|
|
68
|
+
"backoffFactor": 2,
|
|
69
|
+
"maxRetries": -1,
|
|
70
|
+
"connectTimeoutMs": 10000,
|
|
71
|
+
"handshake": {
|
|
72
|
+
"client": "x-channel"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"agents": {
|
|
78
|
+
"defaults": {
|
|
79
|
+
"blockStreamingDefault": "on",
|
|
80
|
+
"blockStreamingBreak": "text_end"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> **Note:** The `host`, `port`, and `endpointPath` configuration options are deprecated. The HTTP route is now integrated directly into the OpenClaw server at `/v1/chat/completions`.
|
|
87
|
+
|
|
88
|
+
Changing `blockStreamingDefault`/`blockStreamingBreak` affects how OpenClaw generates streaming deltas. Set `blockStreaming` in the CLI or config when you need fine-grained token-level streaming.
|
|
89
|
+
|
|
90
|
+
## HTTP inbound protocol
|
|
91
|
+
|
|
92
|
+
### Endpoint
|
|
93
|
+
|
|
94
|
+
`POST http://<openclaw-host>:<openclaw-port>/v1/chat/completions`
|
|
95
|
+
|
|
96
|
+
For local development, this is typically: `http://127.0.0.1:18789/v1/chat/completions`
|
|
97
|
+
|
|
98
|
+
### Request body
|
|
99
|
+
|
|
100
|
+
OpenAI-compatible request shape:
|
|
101
|
+
|
|
102
|
+
| Field | Type | Description |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `model` | string | Optional model label echoed in response |
|
|
105
|
+
| `content` | string/array | Preferred inbound text source; when empty request is ignored |
|
|
106
|
+
| `messages` | array | Required message list (OpenAI format) |
|
|
107
|
+
| `stream` | boolean | `true` for SSE streaming chunks |
|
|
108
|
+
| `user` | string | Optional user ID (mapped to channel sender) |
|
|
109
|
+
| `metadata` | object | Optional passthrough metadata |
|
|
110
|
+
|
|
111
|
+
### Sample `curl` (PowerShell):
|
|
112
|
+
|
|
113
|
+
```powershell
|
|
114
|
+
curl.exe --noproxy "*" -i -X POST "http://127.0.0.1:18789/v1/chat/completions" `
|
|
115
|
+
-H "Content-Type: application/json" `
|
|
116
|
+
--data-raw '{"model":"x-channel","messages":[{"role":"user","content":"hello"}],"stream":false,"user":"u-1"}'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
When `stream=false`, response follows OpenAI `chat.completion` JSON schema.
|
|
120
|
+
When `stream=true` (or omitted), response is SSE with `chat.completion.chunk` events and final `data: [DONE]`.
|
|
121
|
+
|
|
122
|
+
## WS-driven inbound data
|
|
123
|
+
|
|
124
|
+
The outbound WS client becomes active when `channels.x-channel.ws.enabled` is `true` and `channels.x-channel.ws.url` is provided. The client:
|
|
125
|
+
|
|
126
|
+
- Connects to your server using the configured `protocols` list.
|
|
127
|
+
- Supports exponential backoff reconnects controlled by `initialRetryMs`, `maxRetryMs`, `backoffFactor`, and `maxRetries`.
|
|
128
|
+
- Imposes a per-attempt timeout (`connectTimeoutMs`) and immediately retries if the handshake fails.
|
|
129
|
+
- Sends the optional `handshake` payload after the connection opens.
|
|
130
|
+
- Emits detailed logs prefixed by `[x-channel:accountId]` for lifecycle events, connection attempts, and errors.
|
|
131
|
+
|
|
132
|
+
### WS request format (server → plugin client)
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"requestId": "req-1",
|
|
137
|
+
"text": "hello from ws",
|
|
138
|
+
"userId": "u-1",
|
|
139
|
+
"accountId": "default",
|
|
140
|
+
"conversationId": "c-1",
|
|
141
|
+
"metadata": { "source": "ws-server" }
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### WS reply protocol (client → server)
|
|
146
|
+
|
|
147
|
+
1. **Accepted acknowledgement**
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{ "ok": true, "requestId": "req-1", "type": "accepted", "message": "request accepted" }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
2. **Streaming delta frames**
|
|
154
|
+
|
|
155
|
+
Each block produced by OpenClaw is pushed as a delta. Deltas include `index`, `kind`, and `text`. The dispatcher flags `done: true` on the final delta.
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"ok": true,
|
|
160
|
+
"requestId": "req-1",
|
|
161
|
+
"type": "delta",
|
|
162
|
+
"index": 0,
|
|
163
|
+
"kind": "block",
|
|
164
|
+
"text": "...",
|
|
165
|
+
"done": false
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
3. **Completion frame**
|
|
170
|
+
|
|
171
|
+
When OpenClaw generated no deltas, the plugin sends a standalone `done` event:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"ok": true,
|
|
176
|
+
"requestId": "req-1",
|
|
177
|
+
"type": "done",
|
|
178
|
+
"done": true,
|
|
179
|
+
"event": { "...": "..." }
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
When there are deltas, the final delta carries `done: true` and optional `event`/`replies` payloads derived from the final message.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
declare const plugin: {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
configSchema: import("openclaw/plugin-sdk").OpenClawPluginConfigSchema;
|
|
7
|
+
register(api: OpenClawPluginApi): void;
|
|
8
|
+
};
|
|
9
|
+
export default plugin;
|
|
10
|
+
export { xChannelPlugin } from "./src/channel.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAM7D,QAAA,MAAM,MAAM;;;;;kBAMI,iBAAiB;CAWhC,CAAC;AAEF,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
2
|
+
import { xChannelPlugin } from "./src/channel.js";
|
|
3
|
+
import { setXChannelRuntime } from "./src/runtime.js";
|
|
4
|
+
import { createHttpHandler } from "./src/http-handler.js";
|
|
5
|
+
const plugin = {
|
|
6
|
+
id: "x-channel",
|
|
7
|
+
name: "x-channel",
|
|
8
|
+
description: "HTTP bridge channel with OpenClaw-integrated HTTP route.",
|
|
9
|
+
configSchema: emptyPluginConfigSchema(),
|
|
10
|
+
register(api) {
|
|
11
|
+
setXChannelRuntime(api.runtime);
|
|
12
|
+
api.registerChannel({ plugin: xChannelPlugin });
|
|
13
|
+
// Register HTTP route on OpenClaw's main server
|
|
14
|
+
api.registerHttpRoute({
|
|
15
|
+
path: "/v1/chat/completions",
|
|
16
|
+
auth: "plugin",
|
|
17
|
+
handler: createHttpHandler(api),
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
export default plugin;
|
|
22
|
+
export { xChannelPlugin } from "./src/channel.js";
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,MAAM,GAAG;IACb,EAAE,EAAE,WAAW;IACf,IAAI,EAAE,WAAW;IACjB,WAAW,EACT,0DAA0D;IAC5D,YAAY,EAAE,uBAAuB,EAAE;IACvC,QAAQ,CAAC,GAAsB;QAC7B,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;QAEhD,gDAAgD;QAChD,GAAG,CAAC,iBAAiB,CAAC;YACpB,IAAI,EAAE,sBAAsB;YAC5B,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-entry.d.ts","sourceRoot":"","sources":["../setup-entry.ts"],"names":[],"mappings":";;;AAGA,wBAAsD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-entry.js","sourceRoot":"","sources":["../setup-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,eAAe,sBAAsB,CAAC,cAAc,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ChannelPlugin, OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
|
+
export type XChannelResolvedAccount = {
|
|
3
|
+
accountId: string;
|
|
4
|
+
defaultConversationId?: string;
|
|
5
|
+
host: string;
|
|
6
|
+
port: number;
|
|
7
|
+
endpointPath: string;
|
|
8
|
+
ws: {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
url?: string;
|
|
11
|
+
protocols: string[];
|
|
12
|
+
initialRetryMs: number;
|
|
13
|
+
maxRetryMs: number;
|
|
14
|
+
backoffFactor: number;
|
|
15
|
+
maxRetries: number;
|
|
16
|
+
connectTimeoutMs: number;
|
|
17
|
+
handshake?: Record<string, unknown>;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export declare function resolveAccount(cfg: OpenClawConfig, accountId?: string | null): XChannelResolvedAccount;
|
|
21
|
+
export declare const xChannelPlugin: ChannelPlugin<XChannelResolvedAccount>;
|
|
22
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAWzE,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,EAAE,EAAE;QACF,OAAO,EAAE,OAAO,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACH,CAAC;AAgBF,wBAAgB,cAAc,CAC5B,GAAG,EAAE,cAAc,EACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,uBAAuB,CA4DzB;AAED,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC,uBAAuB,CAwF/D,CAAC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { startGateway } from "./gateway.js";
|
|
2
|
+
function logChannel(message, extra) {
|
|
3
|
+
if (extra === undefined) {
|
|
4
|
+
console.log(`[x-channel/channel] ${message}`);
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
console.log(`[x-channel/channel] ${message}`, extra);
|
|
8
|
+
}
|
|
9
|
+
function getSection(cfg) {
|
|
10
|
+
const channels = (cfg.channels ?? {});
|
|
11
|
+
return channels["x-channel"] ?? {};
|
|
12
|
+
}
|
|
13
|
+
function listAccountIds(cfg) {
|
|
14
|
+
const section = getSection(cfg);
|
|
15
|
+
const configured = section.defaultAccountId;
|
|
16
|
+
if (typeof configured === "string" && configured.trim()) {
|
|
17
|
+
return [configured.trim()];
|
|
18
|
+
}
|
|
19
|
+
return ["default"];
|
|
20
|
+
}
|
|
21
|
+
export function resolveAccount(cfg, accountId) {
|
|
22
|
+
const section = getSection(cfg);
|
|
23
|
+
const wsSection = section.ws && typeof section.ws === "object"
|
|
24
|
+
? section.ws
|
|
25
|
+
: {};
|
|
26
|
+
const configuredPort = typeof section.port === "number"
|
|
27
|
+
? section.port
|
|
28
|
+
: typeof section.port === "string"
|
|
29
|
+
? Number(section.port)
|
|
30
|
+
: NaN;
|
|
31
|
+
const wsProtocols = Array.isArray(wsSection.protocols)
|
|
32
|
+
? wsSection.protocols.filter((v) => typeof v === "string")
|
|
33
|
+
: [];
|
|
34
|
+
const wsInitialRetryMs = typeof wsSection.initialRetryMs === "number" ? wsSection.initialRetryMs : 1000;
|
|
35
|
+
const wsMaxRetryMs = typeof wsSection.maxRetryMs === "number" ? wsSection.maxRetryMs : 30000;
|
|
36
|
+
const wsBackoffFactor = typeof wsSection.backoffFactor === "number" ? wsSection.backoffFactor : 2;
|
|
37
|
+
const wsMaxRetries = typeof wsSection.maxRetries === "number" ? wsSection.maxRetries : -1;
|
|
38
|
+
const wsConnectTimeoutMs = typeof wsSection.connectTimeoutMs === "number" ? wsSection.connectTimeoutMs : 10000;
|
|
39
|
+
const resolved = {
|
|
40
|
+
accountId: accountId ?? String(section.defaultAccountId ?? "default"),
|
|
41
|
+
defaultConversationId: typeof section.defaultConversationId === "string"
|
|
42
|
+
? section.defaultConversationId
|
|
43
|
+
: undefined,
|
|
44
|
+
host: typeof section.host === "string" ? section.host : "127.0.0.1",
|
|
45
|
+
port: Number.isFinite(configuredPort) ? configuredPort : 3000,
|
|
46
|
+
endpointPath: typeof section.endpointPath === "string"
|
|
47
|
+
? section.endpointPath
|
|
48
|
+
: "/v1/chat/completions",
|
|
49
|
+
ws: {
|
|
50
|
+
enabled: Boolean(wsSection.enabled),
|
|
51
|
+
url: typeof wsSection.url === "string" ? wsSection.url : undefined,
|
|
52
|
+
protocols: wsProtocols,
|
|
53
|
+
initialRetryMs: Math.max(200, wsInitialRetryMs),
|
|
54
|
+
maxRetryMs: Math.max(1000, wsMaxRetryMs),
|
|
55
|
+
backoffFactor: Math.max(1, wsBackoffFactor),
|
|
56
|
+
maxRetries: wsMaxRetries,
|
|
57
|
+
connectTimeoutMs: Math.max(1000, wsConnectTimeoutMs),
|
|
58
|
+
handshake: wsSection.handshake && typeof wsSection.handshake === "object"
|
|
59
|
+
? wsSection.handshake
|
|
60
|
+
: undefined,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
logChannel("resolveAccount", {
|
|
64
|
+
accountId: resolved.accountId,
|
|
65
|
+
endpoint: `http://${resolved.host}:${resolved.port}${resolved.endpointPath}`,
|
|
66
|
+
wsEnabled: resolved.ws.enabled,
|
|
67
|
+
wsUrl: resolved.ws.url ?? ""
|
|
68
|
+
});
|
|
69
|
+
return resolved;
|
|
70
|
+
}
|
|
71
|
+
export const xChannelPlugin = {
|
|
72
|
+
id: "x-channel",
|
|
73
|
+
meta: {
|
|
74
|
+
id: "x-channel",
|
|
75
|
+
label: "x-channel",
|
|
76
|
+
selectionLabel: "x-channel",
|
|
77
|
+
blurb: "HTTP inbound bridge for OpenClaw.",
|
|
78
|
+
order: 60,
|
|
79
|
+
docsPath: "",
|
|
80
|
+
},
|
|
81
|
+
capabilities: {
|
|
82
|
+
chatTypes: ["direct"],
|
|
83
|
+
media: false,
|
|
84
|
+
reactions: false,
|
|
85
|
+
threads: false,
|
|
86
|
+
blockStreaming: false,
|
|
87
|
+
},
|
|
88
|
+
reload: { configPrefixes: ["channels.x-channel"] },
|
|
89
|
+
config: {
|
|
90
|
+
listAccountIds: (cfg) => listAccountIds(cfg),
|
|
91
|
+
resolveAccount: (cfg, accountId) => resolveAccount(cfg, accountId),
|
|
92
|
+
defaultAccountId: (cfg) => listAccountIds(cfg)[0] ?? "default",
|
|
93
|
+
isConfigured: () => true,
|
|
94
|
+
describeAccount: (account) => ({
|
|
95
|
+
accountId: account?.accountId ?? "default",
|
|
96
|
+
enabled: true,
|
|
97
|
+
configured: true,
|
|
98
|
+
endpoint: `OpenClaw integrated: /v1/chat/completions (HTTP route registered on OpenClaw server)`,
|
|
99
|
+
wsEnabled: account?.ws?.enabled ?? false,
|
|
100
|
+
wsUrl: account?.ws?.url ?? "",
|
|
101
|
+
}),
|
|
102
|
+
},
|
|
103
|
+
outbound: {
|
|
104
|
+
deliveryMode: "direct",
|
|
105
|
+
sendText: async ({ to }) => ({
|
|
106
|
+
channel: "x-channel",
|
|
107
|
+
messageId: `x-channel:${Date.now()}`,
|
|
108
|
+
deliveryHint: `noop outbound to ${String(to ?? "unknown")}`,
|
|
109
|
+
}),
|
|
110
|
+
},
|
|
111
|
+
gateway: {
|
|
112
|
+
startAccount: async (ctx) => {
|
|
113
|
+
const { account, abortSignal, cfg, log } = ctx;
|
|
114
|
+
logChannel("startAccount init", {
|
|
115
|
+
accountId: account.accountId,
|
|
116
|
+
endpoint: `http://${account.host}:${account.port}${account.endpointPath}`,
|
|
117
|
+
wsEnabled: account.ws.enabled,
|
|
118
|
+
wsUrl: account.ws.url ?? ""
|
|
119
|
+
});
|
|
120
|
+
abortSignal.addEventListener("abort", () => logChannel(`abort received for account=${account.accountId}`), { once: true });
|
|
121
|
+
await startGateway({
|
|
122
|
+
account,
|
|
123
|
+
abortSignal,
|
|
124
|
+
cfg,
|
|
125
|
+
log,
|
|
126
|
+
onReady: () => {
|
|
127
|
+
ctx.setStatus({
|
|
128
|
+
...ctx.getStatus(),
|
|
129
|
+
running: true,
|
|
130
|
+
connected: true,
|
|
131
|
+
lastConnectedAt: Date.now(),
|
|
132
|
+
lastError: undefined,
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
onError: (error) => {
|
|
136
|
+
ctx.setStatus({
|
|
137
|
+
...ctx.getStatus(),
|
|
138
|
+
running: false,
|
|
139
|
+
connected: false,
|
|
140
|
+
lastError: error.message,
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
status: {
|
|
147
|
+
defaultRuntime: {
|
|
148
|
+
accountId: "default",
|
|
149
|
+
running: false,
|
|
150
|
+
connected: false,
|
|
151
|
+
lastConnectedAt: null,
|
|
152
|
+
lastError: null,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
|
+
import type { XChannelResolvedAccount } from "./channel.js";
|
|
3
|
+
type GatewayLog = {
|
|
4
|
+
info?: (msg: string) => void;
|
|
5
|
+
warn?: (msg: string) => void;
|
|
6
|
+
error?: (msg: string) => void;
|
|
7
|
+
};
|
|
8
|
+
export declare function startGateway(ctx: {
|
|
9
|
+
account: XChannelResolvedAccount;
|
|
10
|
+
abortSignal: AbortSignal;
|
|
11
|
+
cfg: OpenClawConfig;
|
|
12
|
+
log?: GatewayLog;
|
|
13
|
+
onReady?: () => void;
|
|
14
|
+
onError?: (error: Error) => void;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=gateway.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../src/gateway.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAG5D,KAAK,UAAU,GAAG;IAChB,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AA+ZF,wBAAsB,YAAY,CAAC,GAAG,EAAE;IACtC,OAAO,EAAE,uBAAuB,CAAC;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhB"}
|