@evgenyy/lessinbox-channel 0.1.6
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 +88 -0
- package/dist/index.d.ts +177 -0
- package/dist/index.js +736 -0
- package/dist/index.js.map +1 -0
- package/openclaw.plugin.json +55 -0
- package/package.json +46 -0
- package/skills/lessinbox/SKILL.md +11 -0
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @evgenyy/lessinbox-channel
|
|
2
|
+
|
|
3
|
+
Openclaw channel plugin that sends and receives agent conversation state through Lessinbox.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
- Starts Lessinbox sessions (runs) when needed
|
|
8
|
+
- Posts assistant messages into Lessinbox threads
|
|
9
|
+
- Maintains persistent `conversationId -> { threadId, runId }` mapping (`memory` or `redis`)
|
|
10
|
+
- Opens workspace WebSocket stream and emits realtime inbound events (`message.created`, `interrupt.answered`, `run.state_changed`, etc.)
|
|
11
|
+
- Exposes a channel plugin manifest + Lessinbox skill bundle
|
|
12
|
+
|
|
13
|
+
## Package contents
|
|
14
|
+
|
|
15
|
+
- `dist/index.js` plugin runtime entry
|
|
16
|
+
- `openclaw.plugin.json` manifest
|
|
17
|
+
- `skills/lessinbox/SKILL.md`
|
|
18
|
+
|
|
19
|
+
## Required account config
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"channels": {
|
|
24
|
+
"lessinbox": {
|
|
25
|
+
"accounts": {
|
|
26
|
+
"default": {
|
|
27
|
+
"enabled": true,
|
|
28
|
+
"apiUrl": "https://lessinbox.example.com",
|
|
29
|
+
"apiKey": "<LESSINBOX_API_KEY>",
|
|
30
|
+
"workspaceId": "wrk_xxx",
|
|
31
|
+
"defaultChannelId": "chn_xxx",
|
|
32
|
+
"mappingStore": "redis",
|
|
33
|
+
"redisUrl": "redis://localhost:6379",
|
|
34
|
+
"redisPrefix": "lessinbox:openclaw",
|
|
35
|
+
"workspaceStream": {
|
|
36
|
+
"enabled": true,
|
|
37
|
+
"wsUrl": "wss://lessinbox.example.com/v1/ws",
|
|
38
|
+
"reconnectMs": 1500
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Openclaw wiring expectations
|
|
48
|
+
|
|
49
|
+
The plugin expects Openclaw to call `outbound.sendText(...)` with:
|
|
50
|
+
|
|
51
|
+
- `text` (required)
|
|
52
|
+
- `config` (runtime config object)
|
|
53
|
+
- optional: `accountId`, `channelId`, `title`, `threadId`, `runId`, `conversationId`, `metadata`
|
|
54
|
+
|
|
55
|
+
If `threadId` and `runId` are missing, the plugin will create a new Lessinbox run and use that thread.
|
|
56
|
+
|
|
57
|
+
## Realtime inbound usage
|
|
58
|
+
|
|
59
|
+
The package exports `subscribeToLessinboxEvents(...)` and also exposes `plugin.inbound.subscribe(...)`.
|
|
60
|
+
|
|
61
|
+
Example:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { subscribeToLessinboxEvents } from "@evgenyy/lessinbox-channel"
|
|
65
|
+
|
|
66
|
+
const unsubscribe = subscribeToLessinboxEvents({
|
|
67
|
+
config: runtimeConfig,
|
|
68
|
+
accountId: "default",
|
|
69
|
+
onEvent: async (event) => {
|
|
70
|
+
// event.kind, event.threadId, event.runId, event.conversationId, event.payload
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
On terminal run states (`completed`, `failed`, `canceled`) the plugin clears stored run mapping automatically.
|
|
76
|
+
|
|
77
|
+
## Build
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pnpm --filter @evgenyy/lessinbox-channel build
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Publish
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pnpm --filter @evgenyy/lessinbox-channel build
|
|
87
|
+
npm publish --access public
|
|
88
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
export interface LessinboxWorkspaceStreamConfig {
|
|
2
|
+
enabled?: boolean;
|
|
3
|
+
wsUrl?: string;
|
|
4
|
+
reconnectMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface LessinboxAccountConfig {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
apiUrl: string;
|
|
9
|
+
apiKey: string;
|
|
10
|
+
workspaceId: string;
|
|
11
|
+
defaultChannelId: string;
|
|
12
|
+
mappingStore?: "memory" | "redis";
|
|
13
|
+
redisUrl?: string;
|
|
14
|
+
redisPrefix?: string;
|
|
15
|
+
workspaceStream?: LessinboxWorkspaceStreamConfig;
|
|
16
|
+
}
|
|
17
|
+
export interface RunStartResponse {
|
|
18
|
+
run_id: string;
|
|
19
|
+
session_id?: string;
|
|
20
|
+
thread_id: string;
|
|
21
|
+
status: string;
|
|
22
|
+
session_status?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface MessageCreateResponse {
|
|
25
|
+
message_id: string;
|
|
26
|
+
thread_id: string;
|
|
27
|
+
run_id: string | null;
|
|
28
|
+
session_id?: string | null;
|
|
29
|
+
created_at: string;
|
|
30
|
+
}
|
|
31
|
+
export interface InterruptCreateInput {
|
|
32
|
+
title: string;
|
|
33
|
+
question: string;
|
|
34
|
+
options: Array<{
|
|
35
|
+
id: string;
|
|
36
|
+
label: string;
|
|
37
|
+
}>;
|
|
38
|
+
default_option_id?: string;
|
|
39
|
+
deadline_at?: string;
|
|
40
|
+
impact?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface LessinboxRunRef {
|
|
43
|
+
threadId: string;
|
|
44
|
+
runId: string;
|
|
45
|
+
status?: string;
|
|
46
|
+
}
|
|
47
|
+
export type LessinboxWorkspaceEventKind = "event.appended" | "artifact.ready" | "checkpoint.created" | "checkpoint.resolved" | "run.status" | "thread.summary" | "message.created" | "interrupt.opened" | "interrupt.answered" | "run.state_changed";
|
|
48
|
+
export interface LessinboxWorkspaceEvent {
|
|
49
|
+
kind: string;
|
|
50
|
+
thread_id?: string;
|
|
51
|
+
payload?: unknown;
|
|
52
|
+
}
|
|
53
|
+
export interface LessinboxInboundEvent {
|
|
54
|
+
accountId: string;
|
|
55
|
+
workspaceId: string;
|
|
56
|
+
kind: string;
|
|
57
|
+
threadId?: string;
|
|
58
|
+
runId?: string;
|
|
59
|
+
conversationId?: string;
|
|
60
|
+
payload?: unknown;
|
|
61
|
+
raw: LessinboxWorkspaceEvent;
|
|
62
|
+
}
|
|
63
|
+
export type LessinboxInboundEventHandler = (event: LessinboxInboundEvent) => void | Promise<void>;
|
|
64
|
+
export interface SubscribeToLessinboxEventsInput {
|
|
65
|
+
config: unknown;
|
|
66
|
+
accountId?: string;
|
|
67
|
+
onEvent: LessinboxInboundEventHandler;
|
|
68
|
+
}
|
|
69
|
+
export declare function shutdownLessinboxPluginResources(): Promise<void>;
|
|
70
|
+
export declare class LessinboxApi {
|
|
71
|
+
private readonly apiUrl;
|
|
72
|
+
private readonly apiKey;
|
|
73
|
+
private readonly workspaceId;
|
|
74
|
+
private readonly defaultChannelId;
|
|
75
|
+
constructor(config: LessinboxAccountConfig);
|
|
76
|
+
getApiUrl(): string;
|
|
77
|
+
getWorkspaceId(): string;
|
|
78
|
+
getDefaultChannelId(): string;
|
|
79
|
+
startRun(input: {
|
|
80
|
+
title: string;
|
|
81
|
+
channelId?: string;
|
|
82
|
+
threadId?: string;
|
|
83
|
+
labels?: Record<string, string>;
|
|
84
|
+
metadata?: Record<string, unknown>;
|
|
85
|
+
}): Promise<RunStartResponse>;
|
|
86
|
+
postMessage(input: {
|
|
87
|
+
threadId: string;
|
|
88
|
+
runId?: string;
|
|
89
|
+
text?: string;
|
|
90
|
+
content?: unknown;
|
|
91
|
+
kind?: "text" | "status" | "tool_call" | "tool_result";
|
|
92
|
+
}): Promise<MessageCreateResponse>;
|
|
93
|
+
openInterrupt(runId: string, input: InterruptCreateInput): Promise<{
|
|
94
|
+
interrupt_id: string;
|
|
95
|
+
message_id: string;
|
|
96
|
+
run_id: string;
|
|
97
|
+
session_id?: string;
|
|
98
|
+
status: string;
|
|
99
|
+
}>;
|
|
100
|
+
completeRun(runId: string, summary?: string): Promise<void>;
|
|
101
|
+
failRun(runId: string, error: {
|
|
102
|
+
kind: string;
|
|
103
|
+
message: string;
|
|
104
|
+
details?: Record<string, unknown>;
|
|
105
|
+
}): Promise<void>;
|
|
106
|
+
listThreads(input?: {
|
|
107
|
+
bucket?: "needs_input" | "in_progress" | "done" | "all";
|
|
108
|
+
channelId?: string;
|
|
109
|
+
cursor?: string;
|
|
110
|
+
limit?: number;
|
|
111
|
+
}): Promise<{
|
|
112
|
+
threads: unknown[];
|
|
113
|
+
next_cursor: string | null;
|
|
114
|
+
}>;
|
|
115
|
+
createWorkspaceWsToken(): Promise<{
|
|
116
|
+
token: string;
|
|
117
|
+
expires_at: string;
|
|
118
|
+
}>;
|
|
119
|
+
private request;
|
|
120
|
+
}
|
|
121
|
+
export declare function resolveAccountConfig(config: unknown, accountId?: string): LessinboxAccountConfig;
|
|
122
|
+
type ChannelPluginRuntimeAPI = {
|
|
123
|
+
registerChannel: (input: {
|
|
124
|
+
plugin: unknown;
|
|
125
|
+
}) => void;
|
|
126
|
+
onShutdown?: (handler: () => Promise<void> | void) => void;
|
|
127
|
+
};
|
|
128
|
+
type SendTextInput = {
|
|
129
|
+
text: string;
|
|
130
|
+
accountId?: string;
|
|
131
|
+
config?: unknown;
|
|
132
|
+
channelId?: string;
|
|
133
|
+
title?: string;
|
|
134
|
+
threadId?: string;
|
|
135
|
+
runId?: string;
|
|
136
|
+
conversationId?: string;
|
|
137
|
+
metadata?: Record<string, unknown>;
|
|
138
|
+
};
|
|
139
|
+
type SubscribeInput = {
|
|
140
|
+
config?: unknown;
|
|
141
|
+
accountId?: string;
|
|
142
|
+
onEvent: LessinboxInboundEventHandler;
|
|
143
|
+
};
|
|
144
|
+
declare function sendTextToLessinbox(input: SendTextInput): Promise<{
|
|
145
|
+
ok: boolean;
|
|
146
|
+
threadId: string;
|
|
147
|
+
runId: string;
|
|
148
|
+
}>;
|
|
149
|
+
export declare function subscribeToLessinboxEvents(input: SubscribeToLessinboxEventsInput): () => void;
|
|
150
|
+
declare function subscribeFromPlugin(input: SubscribeInput): () => void;
|
|
151
|
+
export declare function createLessinboxPlugin(): {
|
|
152
|
+
id: string;
|
|
153
|
+
meta: {
|
|
154
|
+
id: string;
|
|
155
|
+
label: string;
|
|
156
|
+
selectionLabel: string;
|
|
157
|
+
docsPath: string;
|
|
158
|
+
blurb: string;
|
|
159
|
+
aliases: string[];
|
|
160
|
+
};
|
|
161
|
+
capabilities: {
|
|
162
|
+
chatTypes: string[];
|
|
163
|
+
};
|
|
164
|
+
config: {
|
|
165
|
+
listAccountIds: (cfg: unknown) => string[];
|
|
166
|
+
resolveAccount: (cfg: unknown, accountId?: string) => LessinboxAccountConfig;
|
|
167
|
+
};
|
|
168
|
+
outbound: {
|
|
169
|
+
deliveryMode: string;
|
|
170
|
+
sendText: typeof sendTextToLessinbox;
|
|
171
|
+
};
|
|
172
|
+
inbound: {
|
|
173
|
+
subscribe: typeof subscribeFromPlugin;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
export default function register(api: ChannelPluginRuntimeAPI): void;
|
|
177
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
import Redis from "ioredis";
|
|
2
|
+
import WebSocket from "ws";
|
|
3
|
+
const DEFAULT_RECONNECT_MS = 1_500;
|
|
4
|
+
const MIN_RECONNECT_MS = 250;
|
|
5
|
+
const TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "canceled"]);
|
|
6
|
+
function normalizeBaseUrl(baseUrl) {
|
|
7
|
+
return baseUrl.replace(/\/+$/, "");
|
|
8
|
+
}
|
|
9
|
+
function toErrorMessage(body, fallback) {
|
|
10
|
+
if (!body || typeof body !== "object") {
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
const maybeMessage = body.message;
|
|
14
|
+
if (typeof maybeMessage === "string" && maybeMessage.trim().length > 0) {
|
|
15
|
+
return maybeMessage;
|
|
16
|
+
}
|
|
17
|
+
const maybeError = body.error;
|
|
18
|
+
if (typeof maybeError === "string" && maybeError.trim().length > 0) {
|
|
19
|
+
return maybeError;
|
|
20
|
+
}
|
|
21
|
+
return fallback;
|
|
22
|
+
}
|
|
23
|
+
function randomIdempotencyKey() {
|
|
24
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
25
|
+
return globalThis.crypto.randomUUID();
|
|
26
|
+
}
|
|
27
|
+
return `li_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
28
|
+
}
|
|
29
|
+
function safeJsonParse(value) {
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(value);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function readPath(source, path) {
|
|
38
|
+
let current = source;
|
|
39
|
+
for (const segment of path) {
|
|
40
|
+
if (!current || typeof current !== "object") {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
current = current[segment];
|
|
44
|
+
}
|
|
45
|
+
return current;
|
|
46
|
+
}
|
|
47
|
+
function asRecord(value) {
|
|
48
|
+
if (!value || typeof value !== "object") {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
function toOptionalString(value) {
|
|
54
|
+
if (typeof value !== "string") {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const trimmed = value.trim();
|
|
58
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
59
|
+
}
|
|
60
|
+
function toOptionalPositiveInteger(value) {
|
|
61
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
62
|
+
return Math.max(MIN_RECONNECT_MS, Math.floor(value));
|
|
63
|
+
}
|
|
64
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
65
|
+
const parsed = Number.parseInt(value, 10);
|
|
66
|
+
if (Number.isFinite(parsed)) {
|
|
67
|
+
return Math.max(MIN_RECONNECT_MS, parsed);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
function resolveWorkspaceStreamConfig(value) {
|
|
73
|
+
const record = asRecord(value);
|
|
74
|
+
if (!record) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
enabled: typeof record.enabled === "boolean" ? record.enabled : undefined,
|
|
79
|
+
wsUrl: toOptionalString(record.wsUrl),
|
|
80
|
+
reconnectMs: toOptionalPositiveInteger(record.reconnectMs)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function resolveMappingStoreKind(value) {
|
|
84
|
+
return value === "redis" ? "redis" : "memory";
|
|
85
|
+
}
|
|
86
|
+
function parseRunRef(value) {
|
|
87
|
+
const record = asRecord(value);
|
|
88
|
+
if (!record) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
const threadId = toOptionalString(record.threadId);
|
|
92
|
+
const runId = toOptionalString(record.runId);
|
|
93
|
+
const status = toOptionalString(record.status);
|
|
94
|
+
if (!threadId || !runId) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
return { threadId, runId, status };
|
|
98
|
+
}
|
|
99
|
+
function extractRunId(payload) {
|
|
100
|
+
const record = asRecord(payload);
|
|
101
|
+
if (!record) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
const directRunId = toOptionalString(record.run_id);
|
|
105
|
+
if (directRunId) {
|
|
106
|
+
return directRunId;
|
|
107
|
+
}
|
|
108
|
+
const directSessionId = toOptionalString(record.session_id);
|
|
109
|
+
if (directSessionId) {
|
|
110
|
+
return directSessionId;
|
|
111
|
+
}
|
|
112
|
+
const message = asRecord(record.message);
|
|
113
|
+
const messageRunId = toOptionalString(message?.run_id);
|
|
114
|
+
if (messageRunId) {
|
|
115
|
+
return messageRunId;
|
|
116
|
+
}
|
|
117
|
+
const messageSessionId = toOptionalString(message?.session_id);
|
|
118
|
+
if (messageSessionId) {
|
|
119
|
+
return messageSessionId;
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
function isLessinboxWorkspaceEvent(value) {
|
|
124
|
+
const record = asRecord(value);
|
|
125
|
+
return Boolean(record && typeof record.kind === "string");
|
|
126
|
+
}
|
|
127
|
+
function normalizeWsData(data) {
|
|
128
|
+
if (typeof data === "string") {
|
|
129
|
+
return data;
|
|
130
|
+
}
|
|
131
|
+
if (Buffer.isBuffer(data)) {
|
|
132
|
+
return data.toString("utf8");
|
|
133
|
+
}
|
|
134
|
+
if (Array.isArray(data)) {
|
|
135
|
+
return Buffer.concat(data).toString("utf8");
|
|
136
|
+
}
|
|
137
|
+
if (data instanceof ArrayBuffer) {
|
|
138
|
+
return Buffer.from(data).toString("utf8");
|
|
139
|
+
}
|
|
140
|
+
return Buffer.from(data).toString("utf8");
|
|
141
|
+
}
|
|
142
|
+
function buildWorkspaceWsEndpoint(apiUrl, wsUrlOverride) {
|
|
143
|
+
if (wsUrlOverride) {
|
|
144
|
+
return wsUrlOverride;
|
|
145
|
+
}
|
|
146
|
+
const url = new URL(normalizeBaseUrl(apiUrl));
|
|
147
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
148
|
+
url.search = "";
|
|
149
|
+
const normalizedPath = url.pathname.replace(/\/+$/, "");
|
|
150
|
+
if (!normalizedPath || normalizedPath === "/") {
|
|
151
|
+
url.pathname = "/v1/ws";
|
|
152
|
+
return url.toString();
|
|
153
|
+
}
|
|
154
|
+
if (normalizedPath.endsWith("/v2")) {
|
|
155
|
+
const prefix = normalizedPath.slice(0, -3);
|
|
156
|
+
url.pathname = `${prefix || ""}/v1/ws`;
|
|
157
|
+
return url.toString();
|
|
158
|
+
}
|
|
159
|
+
if (normalizedPath.endsWith("/v1")) {
|
|
160
|
+
url.pathname = `${normalizedPath}/ws`;
|
|
161
|
+
return url.toString();
|
|
162
|
+
}
|
|
163
|
+
url.pathname = `${normalizedPath}/v1/ws`;
|
|
164
|
+
return url.toString();
|
|
165
|
+
}
|
|
166
|
+
function buildWorkspaceWsUrl(apiUrl, token, wsUrlOverride) {
|
|
167
|
+
const endpoint = new URL(buildWorkspaceWsEndpoint(apiUrl, wsUrlOverride));
|
|
168
|
+
endpoint.searchParams.set("scope", "workspace");
|
|
169
|
+
endpoint.searchParams.set("token", token);
|
|
170
|
+
return endpoint.toString();
|
|
171
|
+
}
|
|
172
|
+
function deriveAccountRuntimeId(accountId) {
|
|
173
|
+
return accountId ?? "default";
|
|
174
|
+
}
|
|
175
|
+
function deriveStoreRegistryKey(accountId, account) {
|
|
176
|
+
return [
|
|
177
|
+
accountId,
|
|
178
|
+
account.workspaceId,
|
|
179
|
+
account.mappingStore ?? "memory",
|
|
180
|
+
account.redisUrl ?? "",
|
|
181
|
+
account.redisPrefix ?? ""
|
|
182
|
+
].join("|");
|
|
183
|
+
}
|
|
184
|
+
function deriveWorkspaceConsumerRegistryKey(accountId, account) {
|
|
185
|
+
return [
|
|
186
|
+
accountId,
|
|
187
|
+
account.workspaceId,
|
|
188
|
+
account.workspaceStream?.wsUrl ?? "",
|
|
189
|
+
account.workspaceStream?.reconnectMs ?? "",
|
|
190
|
+
account.mappingStore ?? "memory",
|
|
191
|
+
account.redisUrl ?? "",
|
|
192
|
+
account.redisPrefix ?? ""
|
|
193
|
+
].join("|");
|
|
194
|
+
}
|
|
195
|
+
function encodeStoreKeySegment(value) {
|
|
196
|
+
return encodeURIComponent(value);
|
|
197
|
+
}
|
|
198
|
+
class MemoryConversationMappingStore {
|
|
199
|
+
constructor() {
|
|
200
|
+
this.conversationToRun = new Map();
|
|
201
|
+
this.runToConversation = new Map();
|
|
202
|
+
}
|
|
203
|
+
async getConversationRun(conversationKey) {
|
|
204
|
+
return this.conversationToRun.get(conversationKey);
|
|
205
|
+
}
|
|
206
|
+
async setConversationRun(conversationKey, run) {
|
|
207
|
+
this.conversationToRun.set(conversationKey, run);
|
|
208
|
+
}
|
|
209
|
+
async deleteConversation(conversationKey) {
|
|
210
|
+
this.conversationToRun.delete(conversationKey);
|
|
211
|
+
}
|
|
212
|
+
async getConversationKeyForRun(runId) {
|
|
213
|
+
return this.runToConversation.get(runId);
|
|
214
|
+
}
|
|
215
|
+
async setConversationKeyForRun(runId, conversationKey) {
|
|
216
|
+
this.runToConversation.set(runId, conversationKey);
|
|
217
|
+
}
|
|
218
|
+
async deleteRun(runId) {
|
|
219
|
+
this.runToConversation.delete(runId);
|
|
220
|
+
}
|
|
221
|
+
async close() {
|
|
222
|
+
this.conversationToRun.clear();
|
|
223
|
+
this.runToConversation.clear();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
class RedisConversationMappingStore {
|
|
227
|
+
constructor(redisUrl, prefix) {
|
|
228
|
+
this.client = new Redis(redisUrl, {
|
|
229
|
+
maxRetriesPerRequest: null
|
|
230
|
+
});
|
|
231
|
+
this.prefix = prefix;
|
|
232
|
+
}
|
|
233
|
+
conversationKey(conversationKey) {
|
|
234
|
+
return `${this.prefix}:conversation:${encodeStoreKeySegment(conversationKey)}`;
|
|
235
|
+
}
|
|
236
|
+
runKey(runId) {
|
|
237
|
+
return `${this.prefix}:run:${encodeStoreKeySegment(runId)}`;
|
|
238
|
+
}
|
|
239
|
+
async getConversationRun(conversationKey) {
|
|
240
|
+
const value = await this.client.get(this.conversationKey(conversationKey));
|
|
241
|
+
if (!value) {
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
return parseRunRef(safeJsonParse(value));
|
|
245
|
+
}
|
|
246
|
+
async setConversationRun(conversationKey, run) {
|
|
247
|
+
await this.client.set(this.conversationKey(conversationKey), JSON.stringify(run));
|
|
248
|
+
}
|
|
249
|
+
async deleteConversation(conversationKey) {
|
|
250
|
+
await this.client.del(this.conversationKey(conversationKey));
|
|
251
|
+
}
|
|
252
|
+
async getConversationKeyForRun(runId) {
|
|
253
|
+
const value = await this.client.get(this.runKey(runId));
|
|
254
|
+
return value ?? undefined;
|
|
255
|
+
}
|
|
256
|
+
async setConversationKeyForRun(runId, conversationKey) {
|
|
257
|
+
await this.client.set(this.runKey(runId), conversationKey);
|
|
258
|
+
}
|
|
259
|
+
async deleteRun(runId) {
|
|
260
|
+
await this.client.del(this.runKey(runId));
|
|
261
|
+
}
|
|
262
|
+
async close() {
|
|
263
|
+
try {
|
|
264
|
+
await this.client.quit();
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
this.client.disconnect();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
class WorkspaceStreamConsumer {
|
|
272
|
+
constructor(options) {
|
|
273
|
+
this.listeners = new Set();
|
|
274
|
+
this.socket = null;
|
|
275
|
+
this.reconnectTimer = null;
|
|
276
|
+
this.running = false;
|
|
277
|
+
this.connecting = false;
|
|
278
|
+
this.options = options;
|
|
279
|
+
}
|
|
280
|
+
start() {
|
|
281
|
+
if (this.running) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
this.running = true;
|
|
285
|
+
void this.connect();
|
|
286
|
+
}
|
|
287
|
+
stop() {
|
|
288
|
+
this.running = false;
|
|
289
|
+
this.connecting = false;
|
|
290
|
+
if (this.reconnectTimer) {
|
|
291
|
+
clearTimeout(this.reconnectTimer);
|
|
292
|
+
this.reconnectTimer = null;
|
|
293
|
+
}
|
|
294
|
+
if (this.socket) {
|
|
295
|
+
const socket = this.socket;
|
|
296
|
+
this.socket = null;
|
|
297
|
+
socket.removeAllListeners();
|
|
298
|
+
try {
|
|
299
|
+
socket.close();
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
socket.terminate();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
this.listeners.clear();
|
|
306
|
+
}
|
|
307
|
+
addListener(listener) {
|
|
308
|
+
this.listeners.add(listener);
|
|
309
|
+
return () => {
|
|
310
|
+
this.listeners.delete(listener);
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
listenerCount() {
|
|
314
|
+
return this.listeners.size;
|
|
315
|
+
}
|
|
316
|
+
scheduleReconnect() {
|
|
317
|
+
if (!this.running || this.reconnectTimer) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
this.reconnectTimer = setTimeout(() => {
|
|
321
|
+
this.reconnectTimer = null;
|
|
322
|
+
void this.connect();
|
|
323
|
+
}, this.options.reconnectMs);
|
|
324
|
+
}
|
|
325
|
+
async connect() {
|
|
326
|
+
if (!this.running || this.connecting) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
this.connecting = true;
|
|
330
|
+
try {
|
|
331
|
+
const tokenResponse = await this.options.api.createWorkspaceWsToken();
|
|
332
|
+
if (!this.running) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const socketUrl = buildWorkspaceWsUrl(this.options.api.getApiUrl(), tokenResponse.token, this.options.wsUrl);
|
|
336
|
+
const socket = new WebSocket(socketUrl);
|
|
337
|
+
this.socket = socket;
|
|
338
|
+
socket.on("message", (data) => {
|
|
339
|
+
void this.handleMessage(data);
|
|
340
|
+
});
|
|
341
|
+
socket.on("close", () => {
|
|
342
|
+
if (this.socket === socket) {
|
|
343
|
+
this.socket = null;
|
|
344
|
+
}
|
|
345
|
+
this.scheduleReconnect();
|
|
346
|
+
});
|
|
347
|
+
socket.on("error", () => {
|
|
348
|
+
// close event handles reconnect scheduling
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
this.scheduleReconnect();
|
|
353
|
+
}
|
|
354
|
+
finally {
|
|
355
|
+
this.connecting = false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
async handleMessage(data) {
|
|
359
|
+
const rawData = normalizeWsData(data);
|
|
360
|
+
if (!rawData) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const parsed = safeJsonParse(rawData);
|
|
364
|
+
if (!isLessinboxWorkspaceEvent(parsed)) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const threadId = toOptionalString(parsed.thread_id);
|
|
368
|
+
const runId = extractRunId(parsed.payload);
|
|
369
|
+
const mappedConversationId = runId
|
|
370
|
+
? await this.options.mappingStore.getConversationKeyForRun(runId)
|
|
371
|
+
: undefined;
|
|
372
|
+
const conversationId = mappedConversationId ?? (threadId ? `thread:${threadId}` : undefined);
|
|
373
|
+
const event = {
|
|
374
|
+
accountId: this.options.accountId,
|
|
375
|
+
workspaceId: this.options.api.getWorkspaceId(),
|
|
376
|
+
kind: parsed.kind,
|
|
377
|
+
threadId,
|
|
378
|
+
runId,
|
|
379
|
+
conversationId,
|
|
380
|
+
payload: parsed.payload,
|
|
381
|
+
raw: parsed
|
|
382
|
+
};
|
|
383
|
+
await this.handleInternalState(event);
|
|
384
|
+
await this.emit(event);
|
|
385
|
+
}
|
|
386
|
+
async handleInternalState(event) {
|
|
387
|
+
if (event.kind !== "run.state_changed" || !event.runId) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const payload = asRecord(event.payload);
|
|
391
|
+
const toStatus = toOptionalString(payload?.to);
|
|
392
|
+
if (!toStatus || !TERMINAL_RUN_STATUSES.has(toStatus)) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const conversationId = event.conversationId ?? (await this.options.mappingStore.getConversationKeyForRun(event.runId));
|
|
396
|
+
if (conversationId) {
|
|
397
|
+
await this.options.mappingStore.deleteConversation(conversationId);
|
|
398
|
+
}
|
|
399
|
+
await this.options.mappingStore.deleteRun(event.runId);
|
|
400
|
+
}
|
|
401
|
+
async emit(event) {
|
|
402
|
+
for (const listener of this.listeners) {
|
|
403
|
+
try {
|
|
404
|
+
await listener(event);
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
// listener failures should not break consumer loop
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const mappingStores = new Map();
|
|
413
|
+
const workspaceConsumers = new Map();
|
|
414
|
+
function createConversationMappingStore(accountId, account) {
|
|
415
|
+
if (account.mappingStore === "redis") {
|
|
416
|
+
if (!account.redisUrl) {
|
|
417
|
+
throw new Error(`Lessinbox account '${accountId}' uses redis mappingStore but redisUrl is missing`);
|
|
418
|
+
}
|
|
419
|
+
const prefix = account.redisPrefix ?? `lessinbox:openclaw:${account.workspaceId}:${accountId}`;
|
|
420
|
+
return new RedisConversationMappingStore(account.redisUrl, prefix);
|
|
421
|
+
}
|
|
422
|
+
return new MemoryConversationMappingStore();
|
|
423
|
+
}
|
|
424
|
+
function getConversationMappingStore(accountId, account) {
|
|
425
|
+
const key = deriveStoreRegistryKey(accountId, account);
|
|
426
|
+
const existing = mappingStores.get(key);
|
|
427
|
+
if (existing) {
|
|
428
|
+
return existing;
|
|
429
|
+
}
|
|
430
|
+
const created = createConversationMappingStore(accountId, account);
|
|
431
|
+
mappingStores.set(key, created);
|
|
432
|
+
return created;
|
|
433
|
+
}
|
|
434
|
+
function ensureWorkspaceConsumer(accountId, account, api, mappingStore) {
|
|
435
|
+
if (account.workspaceStream?.enabled === false) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
const key = deriveWorkspaceConsumerRegistryKey(accountId, account);
|
|
439
|
+
const existing = workspaceConsumers.get(key);
|
|
440
|
+
if (existing) {
|
|
441
|
+
existing.start();
|
|
442
|
+
return existing;
|
|
443
|
+
}
|
|
444
|
+
const consumer = new WorkspaceStreamConsumer({
|
|
445
|
+
accountId,
|
|
446
|
+
api,
|
|
447
|
+
mappingStore,
|
|
448
|
+
wsUrl: account.workspaceStream?.wsUrl,
|
|
449
|
+
reconnectMs: account.workspaceStream?.reconnectMs ?? DEFAULT_RECONNECT_MS
|
|
450
|
+
});
|
|
451
|
+
workspaceConsumers.set(key, consumer);
|
|
452
|
+
consumer.start();
|
|
453
|
+
return consumer;
|
|
454
|
+
}
|
|
455
|
+
export async function shutdownLessinboxPluginResources() {
|
|
456
|
+
for (const consumer of workspaceConsumers.values()) {
|
|
457
|
+
consumer.stop();
|
|
458
|
+
}
|
|
459
|
+
workspaceConsumers.clear();
|
|
460
|
+
for (const store of mappingStores.values()) {
|
|
461
|
+
await store.close();
|
|
462
|
+
}
|
|
463
|
+
mappingStores.clear();
|
|
464
|
+
}
|
|
465
|
+
export class LessinboxApi {
|
|
466
|
+
constructor(config) {
|
|
467
|
+
this.apiUrl = normalizeBaseUrl(config.apiUrl);
|
|
468
|
+
this.apiKey = config.apiKey;
|
|
469
|
+
this.workspaceId = config.workspaceId;
|
|
470
|
+
this.defaultChannelId = config.defaultChannelId;
|
|
471
|
+
}
|
|
472
|
+
getApiUrl() {
|
|
473
|
+
return this.apiUrl;
|
|
474
|
+
}
|
|
475
|
+
getWorkspaceId() {
|
|
476
|
+
return this.workspaceId;
|
|
477
|
+
}
|
|
478
|
+
getDefaultChannelId() {
|
|
479
|
+
return this.defaultChannelId;
|
|
480
|
+
}
|
|
481
|
+
async startRun(input) {
|
|
482
|
+
return this.request("/v2/runs", {
|
|
483
|
+
method: "POST",
|
|
484
|
+
body: {
|
|
485
|
+
title: input.title,
|
|
486
|
+
channel_id: input.channelId ?? this.defaultChannelId,
|
|
487
|
+
thread_id: input.threadId,
|
|
488
|
+
labels: input.labels,
|
|
489
|
+
metadata: input.metadata
|
|
490
|
+
},
|
|
491
|
+
idempotencyKey: randomIdempotencyKey()
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
async postMessage(input) {
|
|
495
|
+
return this.request(`/v2/threads/${input.threadId}/messages`, {
|
|
496
|
+
method: "POST",
|
|
497
|
+
body: {
|
|
498
|
+
run_id: input.runId,
|
|
499
|
+
kind: input.kind ?? "text",
|
|
500
|
+
text: input.text,
|
|
501
|
+
content: input.content
|
|
502
|
+
},
|
|
503
|
+
idempotencyKey: randomIdempotencyKey()
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
async openInterrupt(runId, input) {
|
|
507
|
+
return this.request(`/v2/runs/${runId}/interrupts`, {
|
|
508
|
+
method: "POST",
|
|
509
|
+
body: input,
|
|
510
|
+
idempotencyKey: randomIdempotencyKey()
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
async completeRun(runId, summary) {
|
|
514
|
+
await this.request(`/v2/runs/${runId}/complete`, {
|
|
515
|
+
method: "POST",
|
|
516
|
+
body: summary ? { summary } : {},
|
|
517
|
+
idempotencyKey: randomIdempotencyKey()
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
async failRun(runId, error) {
|
|
521
|
+
await this.request(`/v2/runs/${runId}/fail`, {
|
|
522
|
+
method: "POST",
|
|
523
|
+
body: { error },
|
|
524
|
+
idempotencyKey: randomIdempotencyKey()
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
async listThreads(input = {}) {
|
|
528
|
+
const params = new URLSearchParams();
|
|
529
|
+
if (input.bucket)
|
|
530
|
+
params.set("bucket", input.bucket);
|
|
531
|
+
if (input.channelId)
|
|
532
|
+
params.set("channel_id", input.channelId);
|
|
533
|
+
if (input.cursor)
|
|
534
|
+
params.set("cursor", input.cursor);
|
|
535
|
+
if (typeof input.limit === "number")
|
|
536
|
+
params.set("limit", String(input.limit));
|
|
537
|
+
const query = params.toString();
|
|
538
|
+
return this.request(`/v2/threads${query ? `?${query}` : ""}`, { method: "GET" });
|
|
539
|
+
}
|
|
540
|
+
async createWorkspaceWsToken() {
|
|
541
|
+
return this.request("/v1/workspace/ws-token", {
|
|
542
|
+
method: "POST",
|
|
543
|
+
body: {}
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
async request(path, options) {
|
|
547
|
+
const headers = new Headers({
|
|
548
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
549
|
+
"X-Workspace-Id": this.workspaceId
|
|
550
|
+
});
|
|
551
|
+
if (options.idempotencyKey) {
|
|
552
|
+
headers.set("Idempotency-Key", options.idempotencyKey);
|
|
553
|
+
}
|
|
554
|
+
let body;
|
|
555
|
+
if (options.body !== undefined) {
|
|
556
|
+
headers.set("Content-Type", "application/json");
|
|
557
|
+
body = JSON.stringify(options.body);
|
|
558
|
+
}
|
|
559
|
+
const response = await fetch(`${this.apiUrl}${path}`, {
|
|
560
|
+
method: options.method ?? "GET",
|
|
561
|
+
headers,
|
|
562
|
+
body
|
|
563
|
+
});
|
|
564
|
+
const rawText = await response.text();
|
|
565
|
+
const parsedBody = rawText.length > 0 ? safeJsonParse(rawText) : undefined;
|
|
566
|
+
if (!response.ok) {
|
|
567
|
+
const fallback = `Lessinbox request failed (${response.status})`;
|
|
568
|
+
throw new Error(toErrorMessage(parsedBody, fallback));
|
|
569
|
+
}
|
|
570
|
+
if (!rawText.length) {
|
|
571
|
+
return undefined;
|
|
572
|
+
}
|
|
573
|
+
if (parsedBody !== undefined) {
|
|
574
|
+
return parsedBody;
|
|
575
|
+
}
|
|
576
|
+
throw new Error("Lessinbox response was not valid JSON");
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
export function resolveAccountConfig(config, accountId) {
|
|
580
|
+
const accounts = readPath(config, ["channels", "lessinbox", "accounts"]);
|
|
581
|
+
if (!accounts || typeof accounts !== "object") {
|
|
582
|
+
throw new Error("Missing channels.lessinbox.accounts configuration");
|
|
583
|
+
}
|
|
584
|
+
const resolvedId = accountId ?? "default";
|
|
585
|
+
const account = accounts[resolvedId];
|
|
586
|
+
if (!account || typeof account !== "object") {
|
|
587
|
+
throw new Error(`Lessinbox account '${resolvedId}' is not configured`);
|
|
588
|
+
}
|
|
589
|
+
const apiUrl = account.apiUrl;
|
|
590
|
+
const apiKey = account.apiKey;
|
|
591
|
+
const workspaceId = account.workspaceId;
|
|
592
|
+
const defaultChannelId = account.defaultChannelId;
|
|
593
|
+
if (typeof apiUrl !== "string" ||
|
|
594
|
+
typeof apiKey !== "string" ||
|
|
595
|
+
typeof workspaceId !== "string" ||
|
|
596
|
+
typeof defaultChannelId !== "string") {
|
|
597
|
+
throw new Error(`Lessinbox account '${resolvedId}' is missing required fields (apiUrl, apiKey, workspaceId, defaultChannelId)`);
|
|
598
|
+
}
|
|
599
|
+
const mappingStore = resolveMappingStoreKind(account.mappingStore);
|
|
600
|
+
return {
|
|
601
|
+
enabled: typeof account.enabled === "boolean" ? account.enabled : true,
|
|
602
|
+
apiUrl,
|
|
603
|
+
apiKey,
|
|
604
|
+
workspaceId,
|
|
605
|
+
defaultChannelId,
|
|
606
|
+
mappingStore,
|
|
607
|
+
redisUrl: toOptionalString(account.redisUrl),
|
|
608
|
+
redisPrefix: toOptionalString(account.redisPrefix),
|
|
609
|
+
workspaceStream: resolveWorkspaceStreamConfig(account.workspaceStream)
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
function deriveConversationKey(input) {
|
|
613
|
+
if (input.conversationId && input.conversationId.trim().length > 0) {
|
|
614
|
+
return input.conversationId;
|
|
615
|
+
}
|
|
616
|
+
if (input.threadId && input.threadId.trim().length > 0) {
|
|
617
|
+
return `thread:${input.threadId}`;
|
|
618
|
+
}
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
async function sendTextToLessinbox(input) {
|
|
622
|
+
if (!input.config) {
|
|
623
|
+
throw new Error("Plugin sendText did not receive runtime config");
|
|
624
|
+
}
|
|
625
|
+
const accountRuntimeId = deriveAccountRuntimeId(input.accountId);
|
|
626
|
+
const account = resolveAccountConfig(input.config, accountRuntimeId);
|
|
627
|
+
if (account.enabled === false) {
|
|
628
|
+
throw new Error("Lessinbox account is disabled");
|
|
629
|
+
}
|
|
630
|
+
const api = new LessinboxApi(account);
|
|
631
|
+
const mappingStore = getConversationMappingStore(accountRuntimeId, account);
|
|
632
|
+
ensureWorkspaceConsumer(accountRuntimeId, account, api, mappingStore);
|
|
633
|
+
const conversationKey = deriveConversationKey(input);
|
|
634
|
+
const mappedRun = conversationKey ? await mappingStore.getConversationRun(conversationKey) : undefined;
|
|
635
|
+
let threadId = input.threadId ?? mappedRun?.threadId;
|
|
636
|
+
let runId = input.runId ?? mappedRun?.runId;
|
|
637
|
+
if (!threadId || !runId) {
|
|
638
|
+
const title = (input.title && input.title.trim().length > 0 ? input.title.trim() : null) ??
|
|
639
|
+
input.text.slice(0, 80);
|
|
640
|
+
const started = await api.startRun({
|
|
641
|
+
title,
|
|
642
|
+
channelId: input.channelId ?? api.getDefaultChannelId(),
|
|
643
|
+
metadata: input.metadata
|
|
644
|
+
});
|
|
645
|
+
threadId = started.thread_id;
|
|
646
|
+
runId = started.run_id;
|
|
647
|
+
}
|
|
648
|
+
await api.postMessage({
|
|
649
|
+
threadId,
|
|
650
|
+
runId,
|
|
651
|
+
text: input.text,
|
|
652
|
+
kind: "text"
|
|
653
|
+
});
|
|
654
|
+
if (conversationKey) {
|
|
655
|
+
if (mappedRun?.runId && mappedRun.runId !== runId) {
|
|
656
|
+
await mappingStore.deleteRun(mappedRun.runId);
|
|
657
|
+
}
|
|
658
|
+
await mappingStore.setConversationRun(conversationKey, { threadId, runId });
|
|
659
|
+
await mappingStore.setConversationKeyForRun(runId, conversationKey);
|
|
660
|
+
}
|
|
661
|
+
return {
|
|
662
|
+
ok: true,
|
|
663
|
+
threadId,
|
|
664
|
+
runId
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
export function subscribeToLessinboxEvents(input) {
|
|
668
|
+
const accountRuntimeId = deriveAccountRuntimeId(input.accountId);
|
|
669
|
+
const account = resolveAccountConfig(input.config, accountRuntimeId);
|
|
670
|
+
if (account.enabled === false) {
|
|
671
|
+
throw new Error("Lessinbox account is disabled");
|
|
672
|
+
}
|
|
673
|
+
const api = new LessinboxApi(account);
|
|
674
|
+
const mappingStore = getConversationMappingStore(accountRuntimeId, account);
|
|
675
|
+
const consumer = ensureWorkspaceConsumer(accountRuntimeId, account, api, mappingStore);
|
|
676
|
+
if (!consumer) {
|
|
677
|
+
throw new Error(`Lessinbox workspace stream is disabled for account '${accountRuntimeId}'`);
|
|
678
|
+
}
|
|
679
|
+
return consumer.addListener(input.onEvent);
|
|
680
|
+
}
|
|
681
|
+
function subscribeFromPlugin(input) {
|
|
682
|
+
if (!input.config) {
|
|
683
|
+
throw new Error("Plugin inbound.subscribe did not receive runtime config");
|
|
684
|
+
}
|
|
685
|
+
return subscribeToLessinboxEvents({
|
|
686
|
+
config: input.config,
|
|
687
|
+
accountId: input.accountId,
|
|
688
|
+
onEvent: input.onEvent
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
const plugin = {
|
|
692
|
+
id: "lessinbox",
|
|
693
|
+
meta: {
|
|
694
|
+
id: "lessinbox",
|
|
695
|
+
label: "Lessinbox",
|
|
696
|
+
selectionLabel: "Lessinbox (AI Inbox)",
|
|
697
|
+
docsPath: "/channels/lessinbox",
|
|
698
|
+
blurb: "Use Lessinbox as chat-first interface for Openclaw agents.",
|
|
699
|
+
aliases: ["li", "lessinbox"]
|
|
700
|
+
},
|
|
701
|
+
capabilities: {
|
|
702
|
+
chatTypes: ["direct", "thread"]
|
|
703
|
+
},
|
|
704
|
+
config: {
|
|
705
|
+
listAccountIds: (cfg) => {
|
|
706
|
+
const accounts = readPath(cfg, ["channels", "lessinbox", "accounts"]);
|
|
707
|
+
if (!accounts || typeof accounts !== "object") {
|
|
708
|
+
return [];
|
|
709
|
+
}
|
|
710
|
+
return Object.keys(accounts);
|
|
711
|
+
},
|
|
712
|
+
resolveAccount: (cfg, accountId) => resolveAccountConfig(cfg, accountId)
|
|
713
|
+
},
|
|
714
|
+
outbound: {
|
|
715
|
+
deliveryMode: "direct",
|
|
716
|
+
sendText: sendTextToLessinbox
|
|
717
|
+
},
|
|
718
|
+
inbound: {
|
|
719
|
+
subscribe: subscribeFromPlugin
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
export function createLessinboxPlugin() {
|
|
723
|
+
return plugin;
|
|
724
|
+
}
|
|
725
|
+
export default function register(api) {
|
|
726
|
+
if (!api || typeof api.registerChannel !== "function") {
|
|
727
|
+
throw new Error("Openclaw plugin runtime did not expose registerChannel");
|
|
728
|
+
}
|
|
729
|
+
api.registerChannel({ plugin });
|
|
730
|
+
if (typeof api.onShutdown === "function") {
|
|
731
|
+
api.onShutdown(async () => {
|
|
732
|
+
await shutdownLessinboxPluginResources();
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "lessinbox-channel",
|
|
3
|
+
"name": "Lessinbox Openclaw Channel",
|
|
4
|
+
"description": "Openclaw channel plugin for Lessinbox sessions, messages, and interrupts.",
|
|
5
|
+
"channels": ["lessinbox"],
|
|
6
|
+
"skills": ["skills"],
|
|
7
|
+
"configSchema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"additionalProperties": true,
|
|
10
|
+
"properties": {
|
|
11
|
+
"channels": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"additionalProperties": true,
|
|
14
|
+
"properties": {
|
|
15
|
+
"lessinbox": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": true,
|
|
18
|
+
"properties": {
|
|
19
|
+
"accounts": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"additionalProperties": true,
|
|
24
|
+
"properties": {
|
|
25
|
+
"enabled": { "type": "boolean" },
|
|
26
|
+
"apiUrl": { "type": "string" },
|
|
27
|
+
"apiKey": { "type": "string" },
|
|
28
|
+
"workspaceId": { "type": "string" },
|
|
29
|
+
"defaultChannelId": { "type": "string" },
|
|
30
|
+
"mappingStore": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"enum": ["memory", "redis"]
|
|
33
|
+
},
|
|
34
|
+
"redisUrl": { "type": "string" },
|
|
35
|
+
"redisPrefix": { "type": "string" },
|
|
36
|
+
"workspaceStream": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": true,
|
|
39
|
+
"properties": {
|
|
40
|
+
"enabled": { "type": "boolean" },
|
|
41
|
+
"wsUrl": { "type": "string" },
|
|
42
|
+
"reconnectMs": { "type": "number" }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"required": ["apiUrl", "apiKey", "workspaceId", "defaultChannelId"]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evgenyy/lessinbox-channel",
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"openclaw.plugin.json",
|
|
11
|
+
"skills",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"ioredis": "^5.4.1",
|
|
19
|
+
"ws": "^8.18.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/ws": "^8.18.1"
|
|
23
|
+
},
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"openclaw": {
|
|
31
|
+
"extensions": [
|
|
32
|
+
"./dist/index.js"
|
|
33
|
+
],
|
|
34
|
+
"channel": {
|
|
35
|
+
"id": "lessinbox",
|
|
36
|
+
"label": "Lessinbox",
|
|
37
|
+
"selectionLabel": "Lessinbox (AI Inbox)",
|
|
38
|
+
"docsPath": "/channels/lessinbox",
|
|
39
|
+
"blurb": "Use Lessinbox threads as an Openclaw channel."
|
|
40
|
+
},
|
|
41
|
+
"install": {
|
|
42
|
+
"npmSpec": "@evgenyy/lessinbox-channel",
|
|
43
|
+
"defaultChoice": "npm"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lessinbox
|
|
3
|
+
description: Use Lessinbox threads as the primary human interface for Openclaw sessions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
When running through the Lessinbox channel:
|
|
7
|
+
- Keep updates concise and post progress frequently.
|
|
8
|
+
- Use interrupts for meaningful human decisions only.
|
|
9
|
+
- Provide context, options, and impact when asking for input.
|
|
10
|
+
- When the task is done, post a clear summary and close the session.
|
|
11
|
+
- Keep all execution state in-thread so the conversation is auditable.
|