@evgenyy/lessinbox-channel 0.1.6 → 0.1.9
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 +23 -6
- package/dist/index.d.ts +136 -16
- package/dist/index.js +695 -46
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/skills/lessinbox/SKILL.md +2 -1
package/README.md
CHANGED
|
@@ -4,9 +4,10 @@ Openclaw channel plugin that sends and receives agent conversation state through
|
|
|
4
4
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- Keeps one continuous conversation per target (`channel:*` or `thread:*`)
|
|
8
|
+
- Starts new Lessinbox sessions (runs) only when needed
|
|
8
9
|
- Posts assistant messages into Lessinbox threads
|
|
9
|
-
- Maintains persistent `conversationId -> { threadId, runId }` mapping (`memory` or `redis`)
|
|
10
|
+
- Maintains persistent `conversationId -> { threadId, runId? }` mapping (`memory` or `redis`)
|
|
10
11
|
- Opens workspace WebSocket stream and emits realtime inbound events (`message.created`, `interrupt.answered`, `run.state_changed`, etc.)
|
|
11
12
|
- Exposes a channel plugin manifest + Lessinbox skill bundle
|
|
12
13
|
|
|
@@ -22,6 +23,7 @@ Openclaw channel plugin that sends and receives agent conversation state through
|
|
|
22
23
|
{
|
|
23
24
|
"channels": {
|
|
24
25
|
"lessinbox": {
|
|
26
|
+
"enabled": true,
|
|
25
27
|
"accounts": {
|
|
26
28
|
"default": {
|
|
27
29
|
"enabled": true,
|
|
@@ -34,7 +36,7 @@ Openclaw channel plugin that sends and receives agent conversation state through
|
|
|
34
36
|
"redisPrefix": "lessinbox:openclaw",
|
|
35
37
|
"workspaceStream": {
|
|
36
38
|
"enabled": true,
|
|
37
|
-
"wsUrl": "wss://lessinbox.example.com/
|
|
39
|
+
"wsUrl": "wss://lessinbox.example.com/v2/ws",
|
|
38
40
|
"reconnectMs": 1500
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -50,13 +52,20 @@ The plugin expects Openclaw to call `outbound.sendText(...)` with:
|
|
|
50
52
|
|
|
51
53
|
- `text` (required)
|
|
52
54
|
- `config` (runtime config object)
|
|
53
|
-
- optional: `accountId`, `channelId`, `title`, `threadId`, `runId`, `conversationId`, `metadata`
|
|
55
|
+
- optional: `accountId`, `target`, `channelId`, `title`, `threadId`, `runId`, `conversationId`, `metadata`
|
|
54
56
|
|
|
55
57
|
If `threadId` and `runId` are missing, the plugin will create a new Lessinbox run and use that thread.
|
|
56
58
|
|
|
59
|
+
Target formats supported by the plugin:
|
|
60
|
+
|
|
61
|
+
- `channel:<channelId>` - continue the latest thread for this channel (or create one if missing)
|
|
62
|
+
- `thread:<threadId>` - create/continue conversation in that exact thread
|
|
63
|
+
- raw channel id (`cml...` or `chn_...`) - treated as `channel:<id>`
|
|
64
|
+
- account alias (`default`, etc.) - switches account when it matches configured account id
|
|
65
|
+
|
|
57
66
|
## Realtime inbound usage
|
|
58
67
|
|
|
59
|
-
The package exports `subscribeToLessinboxEvents(...)`
|
|
68
|
+
The package exports `subscribeToLessinboxEvents(...)` as a direct helper for custom integrations.
|
|
60
69
|
|
|
61
70
|
Example:
|
|
62
71
|
|
|
@@ -72,7 +81,15 @@ const unsubscribe = subscribeToLessinboxEvents({
|
|
|
72
81
|
})
|
|
73
82
|
```
|
|
74
83
|
|
|
75
|
-
|
|
84
|
+
For Openclaw-native runtime lifecycle, inbound processing is wired through channel gateway hooks:
|
|
85
|
+
|
|
86
|
+
- `plugin.gateway.startAccount(...)` subscribes to Lessinbox workspace stream.
|
|
87
|
+
- `plugin.gateway.stopAccount(...)` unsubscribes and shuts down account listeners.
|
|
88
|
+
- Incoming `message.created` user messages are routed through Openclaw runtime reply dispatcher.
|
|
89
|
+
|
|
90
|
+
This is the preferred runtime path in v2.
|
|
91
|
+
|
|
92
|
+
On terminal run states (`completed`, `failed`, `canceled`) the plugin keeps thread mapping and clears only the run id, so the next outbound message starts a fresh run in the same thread.
|
|
76
93
|
|
|
77
94
|
## Build
|
|
78
95
|
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export interface LessinboxWorkspaceStreamConfig {
|
|
|
4
4
|
reconnectMs?: number;
|
|
5
5
|
}
|
|
6
6
|
export interface LessinboxAccountConfig {
|
|
7
|
+
accountId?: string;
|
|
7
8
|
enabled?: boolean;
|
|
8
9
|
apiUrl: string;
|
|
9
10
|
apiKey: string;
|
|
@@ -41,9 +42,64 @@ export interface InterruptCreateInput {
|
|
|
41
42
|
}
|
|
42
43
|
export interface LessinboxRunRef {
|
|
43
44
|
threadId: string;
|
|
44
|
-
runId
|
|
45
|
+
runId?: string;
|
|
45
46
|
status?: string;
|
|
46
47
|
}
|
|
48
|
+
interface V2RunSnapshot {
|
|
49
|
+
id: string;
|
|
50
|
+
thread_id: string | null;
|
|
51
|
+
channel_id: string;
|
|
52
|
+
status: string;
|
|
53
|
+
}
|
|
54
|
+
interface V2RunGetResponse {
|
|
55
|
+
run: V2RunSnapshot;
|
|
56
|
+
}
|
|
57
|
+
interface V2ThreadRunSnapshot {
|
|
58
|
+
id: string;
|
|
59
|
+
status: string;
|
|
60
|
+
}
|
|
61
|
+
interface V2ThreadGetResponse {
|
|
62
|
+
id: string;
|
|
63
|
+
channel_id: string;
|
|
64
|
+
run: V2ThreadRunSnapshot | null;
|
|
65
|
+
session?: V2ThreadRunSnapshot | null;
|
|
66
|
+
}
|
|
67
|
+
interface V2ThreadSummary {
|
|
68
|
+
id: string;
|
|
69
|
+
channel_id: string;
|
|
70
|
+
run_id: string | null;
|
|
71
|
+
run_status: string | null;
|
|
72
|
+
session_id?: string | null;
|
|
73
|
+
session_status?: string | null;
|
|
74
|
+
}
|
|
75
|
+
interface V2ThreadListResponse {
|
|
76
|
+
threads: V2ThreadSummary[];
|
|
77
|
+
next_cursor: string | null;
|
|
78
|
+
}
|
|
79
|
+
interface V2MessageActor {
|
|
80
|
+
type?: string;
|
|
81
|
+
user_id?: string;
|
|
82
|
+
userId?: string;
|
|
83
|
+
agent_id?: string;
|
|
84
|
+
agentId?: string;
|
|
85
|
+
}
|
|
86
|
+
interface V2ThreadFeedMessage {
|
|
87
|
+
id: string;
|
|
88
|
+
run_id?: string | null;
|
|
89
|
+
session_id?: string | null;
|
|
90
|
+
kind?: string | null;
|
|
91
|
+
text?: string | null;
|
|
92
|
+
actor?: V2MessageActor;
|
|
93
|
+
created_at?: string;
|
|
94
|
+
}
|
|
95
|
+
interface V2ThreadFeedEntry {
|
|
96
|
+
type?: string;
|
|
97
|
+
message?: V2ThreadFeedMessage;
|
|
98
|
+
}
|
|
99
|
+
interface V2ThreadFeedResponse {
|
|
100
|
+
entries: V2ThreadFeedEntry[];
|
|
101
|
+
next_cursor: string | null;
|
|
102
|
+
}
|
|
47
103
|
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
104
|
export interface LessinboxWorkspaceEvent {
|
|
49
105
|
kind: string;
|
|
@@ -103,32 +159,64 @@ export declare class LessinboxApi {
|
|
|
103
159
|
message: string;
|
|
104
160
|
details?: Record<string, unknown>;
|
|
105
161
|
}): Promise<void>;
|
|
162
|
+
getRun(runId: string): Promise<V2RunGetResponse>;
|
|
163
|
+
getThread(threadId: string): Promise<V2ThreadGetResponse>;
|
|
106
164
|
listThreads(input?: {
|
|
107
165
|
bucket?: "needs_input" | "in_progress" | "done" | "all";
|
|
108
166
|
channelId?: string;
|
|
109
167
|
cursor?: string;
|
|
110
168
|
limit?: number;
|
|
111
|
-
}): Promise<
|
|
112
|
-
threads: unknown[];
|
|
113
|
-
next_cursor: string | null;
|
|
114
|
-
}>;
|
|
169
|
+
}): Promise<V2ThreadListResponse>;
|
|
115
170
|
createWorkspaceWsToken(): Promise<{
|
|
116
171
|
token: string;
|
|
117
172
|
expires_at: string;
|
|
118
173
|
}>;
|
|
174
|
+
getThreadFeed(input: {
|
|
175
|
+
threadId: string;
|
|
176
|
+
limit?: number;
|
|
177
|
+
cursor?: string;
|
|
178
|
+
}): Promise<V2ThreadFeedResponse>;
|
|
119
179
|
private request;
|
|
120
180
|
}
|
|
121
181
|
export declare function resolveAccountConfig(config: unknown, accountId?: string): LessinboxAccountConfig;
|
|
122
|
-
type
|
|
182
|
+
type ChannelLogSink = {
|
|
183
|
+
debug?: (message: string) => void;
|
|
184
|
+
info?: (message: string) => void;
|
|
185
|
+
warn?: (message: string) => void;
|
|
186
|
+
error?: (message: string) => void;
|
|
187
|
+
};
|
|
188
|
+
type ChannelRuntimeState = Record<string, unknown>;
|
|
189
|
+
type ChannelGatewayContext = {
|
|
190
|
+
cfg: unknown;
|
|
191
|
+
accountId: string;
|
|
192
|
+
account: LessinboxAccountConfig;
|
|
193
|
+
runtime: unknown;
|
|
194
|
+
abortSignal: AbortSignal;
|
|
195
|
+
log?: ChannelLogSink;
|
|
196
|
+
getStatus: () => ChannelRuntimeState;
|
|
197
|
+
setStatus: (next: ChannelRuntimeState) => void;
|
|
198
|
+
};
|
|
199
|
+
type ChannelGatewayStartContext = ChannelGatewayContext;
|
|
200
|
+
type ChannelGatewayStopContext = ChannelGatewayContext;
|
|
201
|
+
type OpenclawPluginService = {
|
|
202
|
+
id: string;
|
|
203
|
+
start: (ctx: unknown) => void | Promise<void>;
|
|
204
|
+
stop?: (ctx: unknown) => void | Promise<void>;
|
|
205
|
+
};
|
|
206
|
+
type OpenclawPluginApi = {
|
|
207
|
+
runtime?: unknown;
|
|
123
208
|
registerChannel: (input: {
|
|
124
209
|
plugin: unknown;
|
|
125
|
-
}) => void;
|
|
126
|
-
|
|
210
|
+
} | unknown) => void;
|
|
211
|
+
registerService?: (service: OpenclawPluginService) => void;
|
|
127
212
|
};
|
|
128
213
|
type SendTextInput = {
|
|
129
214
|
text: string;
|
|
130
215
|
accountId?: string;
|
|
131
216
|
config?: unknown;
|
|
217
|
+
target?: string;
|
|
218
|
+
to?: string;
|
|
219
|
+
recipient?: string;
|
|
132
220
|
channelId?: string;
|
|
133
221
|
title?: string;
|
|
134
222
|
threadId?: string;
|
|
@@ -136,18 +224,23 @@ type SendTextInput = {
|
|
|
136
224
|
conversationId?: string;
|
|
137
225
|
metadata?: Record<string, unknown>;
|
|
138
226
|
};
|
|
139
|
-
type
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
onEvent: LessinboxInboundEventHandler;
|
|
227
|
+
type SendMediaInput = Omit<SendTextInput, "text"> & {
|
|
228
|
+
text?: string;
|
|
229
|
+
mediaUrl?: string;
|
|
143
230
|
};
|
|
144
231
|
declare function sendTextToLessinbox(input: SendTextInput): Promise<{
|
|
145
232
|
ok: boolean;
|
|
146
233
|
threadId: string;
|
|
147
234
|
runId: string;
|
|
148
235
|
}>;
|
|
236
|
+
declare function sendMediaToLessinbox(input: SendMediaInput): Promise<{
|
|
237
|
+
ok: boolean;
|
|
238
|
+
threadId: string;
|
|
239
|
+
runId: string;
|
|
240
|
+
}>;
|
|
241
|
+
declare function startLessinboxGatewayAccount(ctx: ChannelGatewayStartContext): Promise<void>;
|
|
242
|
+
declare function stopLessinboxGatewayAccount(ctx: ChannelGatewayStopContext): Promise<void>;
|
|
149
243
|
export declare function subscribeToLessinboxEvents(input: SubscribeToLessinboxEventsInput): () => void;
|
|
150
|
-
declare function subscribeFromPlugin(input: SubscribeInput): () => void;
|
|
151
244
|
export declare function createLessinboxPlugin(): {
|
|
152
245
|
id: string;
|
|
153
246
|
meta: {
|
|
@@ -160,18 +253,45 @@ export declare function createLessinboxPlugin(): {
|
|
|
160
253
|
};
|
|
161
254
|
capabilities: {
|
|
162
255
|
chatTypes: string[];
|
|
256
|
+
threads: boolean;
|
|
257
|
+
media: boolean;
|
|
258
|
+
};
|
|
259
|
+
reload: {
|
|
260
|
+
configPrefixes: string[];
|
|
163
261
|
};
|
|
164
262
|
config: {
|
|
165
263
|
listAccountIds: (cfg: unknown) => string[];
|
|
166
264
|
resolveAccount: (cfg: unknown, accountId?: string) => LessinboxAccountConfig;
|
|
265
|
+
isConfigured: (account: LessinboxAccountConfig) => boolean;
|
|
266
|
+
describeAccount: (account: LessinboxAccountConfig) => {
|
|
267
|
+
accountId: string;
|
|
268
|
+
enabled: boolean;
|
|
269
|
+
configured: boolean;
|
|
270
|
+
workspaceId: string;
|
|
271
|
+
apiUrl: string;
|
|
272
|
+
};
|
|
167
273
|
};
|
|
168
274
|
outbound: {
|
|
169
275
|
deliveryMode: string;
|
|
170
276
|
sendText: typeof sendTextToLessinbox;
|
|
277
|
+
sendMedia: typeof sendMediaToLessinbox;
|
|
278
|
+
};
|
|
279
|
+
gateway: {
|
|
280
|
+
startAccount: typeof startLessinboxGatewayAccount;
|
|
281
|
+
stopAccount: typeof stopLessinboxGatewayAccount;
|
|
171
282
|
};
|
|
172
|
-
|
|
173
|
-
|
|
283
|
+
status: {
|
|
284
|
+
defaultRuntime: {
|
|
285
|
+
accountId: string;
|
|
286
|
+
running: boolean;
|
|
287
|
+
connected: boolean;
|
|
288
|
+
lastConnectedAt: null;
|
|
289
|
+
lastDisconnect: null;
|
|
290
|
+
lastStartAt: null;
|
|
291
|
+
lastStopAt: null;
|
|
292
|
+
lastError: null;
|
|
293
|
+
};
|
|
174
294
|
};
|
|
175
295
|
};
|
|
176
|
-
export default function register(api:
|
|
296
|
+
export default function register(api: OpenclawPluginApi): void;
|
|
177
297
|
export {};
|