@claw-manager/openclaw-api-channel 2026.6.27
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 +5 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/src/channel.js +188 -0
- package/dist/src/channel.js.map +1 -0
- package/index.ts +12 -0
- package/openclaw.plugin.json +22 -0
- package/package.json +65 -0
- package/src/channel.ts +236 -0
package/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Claw Manager API Channel
|
|
2
|
+
|
|
3
|
+
OpenClaw channel plugin used by Claw Manager to deliver external API messages into the normal OpenClaw agent runtime.
|
|
4
|
+
|
|
5
|
+
The plugin expects Claw Manager to call the Gateway method `claw-manager-api.sendMessage`. It receives pre-derived sender identity and OpenViking user identity, then records an inbound session message and dispatches the reply through OpenClaw.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { apiChannelPlugin } from "./src/channel.js";
|
|
2
|
+
export default {
|
|
3
|
+
id: "claw-manager-api",
|
|
4
|
+
name: "Claw Manager API",
|
|
5
|
+
description: "External API channel for Claw Manager",
|
|
6
|
+
register(api) {
|
|
7
|
+
api.registerChannel({ plugin: apiChannelPlugin });
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,eAAe;IACb,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,uCAAuC;IACpD,QAAQ,CAAC,GAAsB;QAC7B,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime";
|
|
3
|
+
export function buildApiInboundContext(params) {
|
|
4
|
+
const message = trim(params.message);
|
|
5
|
+
const openVikingUserId = trim(params.openVikingUserId) || trim(params.openvikingUserId);
|
|
6
|
+
const senderHash = trim(params.senderHash);
|
|
7
|
+
const senderId = trim(params.senderId) || (senderHash ? `api:${senderHash}` : "");
|
|
8
|
+
const conversationHash = trim(params.conversationHash);
|
|
9
|
+
if (!message) {
|
|
10
|
+
throw new Error("message is required");
|
|
11
|
+
}
|
|
12
|
+
if (!openVikingUserId) {
|
|
13
|
+
throw new Error("openVikingUserId is required");
|
|
14
|
+
}
|
|
15
|
+
if (!senderHash) {
|
|
16
|
+
throw new Error("senderHash is required");
|
|
17
|
+
}
|
|
18
|
+
if (!conversationHash) {
|
|
19
|
+
throw new Error("conversationHash is required");
|
|
20
|
+
}
|
|
21
|
+
const from = `api:${senderHash}`;
|
|
22
|
+
const to = `api:${senderHash}:${conversationHash}`;
|
|
23
|
+
return {
|
|
24
|
+
Body: message,
|
|
25
|
+
Text: message,
|
|
26
|
+
From: from,
|
|
27
|
+
To: to,
|
|
28
|
+
AccountId: "global",
|
|
29
|
+
OriginatingChannel: "claw-manager-api",
|
|
30
|
+
OriginatingTo: to,
|
|
31
|
+
MessageSid: `claw-manager-api-${randomUUID()}`,
|
|
32
|
+
Timestamp: Date.now(),
|
|
33
|
+
Provider: "claw-manager-api",
|
|
34
|
+
ChatType: "direct",
|
|
35
|
+
SessionKey: `api:${senderHash}:${conversationHash}`,
|
|
36
|
+
SenderId: senderId,
|
|
37
|
+
senderId,
|
|
38
|
+
requesterSenderId: senderId,
|
|
39
|
+
openVikingUserId,
|
|
40
|
+
openvikingUserId: openVikingUserId,
|
|
41
|
+
Metadata: params.metadata ?? {},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export async function dispatchApiMessage(ctx) {
|
|
45
|
+
if (!ctx.channelRuntime) {
|
|
46
|
+
throw new Error("ctx.channelRuntime missing");
|
|
47
|
+
}
|
|
48
|
+
if (!ctx.cfg) {
|
|
49
|
+
throw new Error("ctx.cfg missing");
|
|
50
|
+
}
|
|
51
|
+
const runtime = ctx.channelRuntime;
|
|
52
|
+
const inbound = buildApiInboundContext(ctx);
|
|
53
|
+
const route = runtime.routing.resolveAgentRoute({
|
|
54
|
+
cfg: ctx.cfg,
|
|
55
|
+
channel: "claw-manager-api",
|
|
56
|
+
accountId: "global",
|
|
57
|
+
peer: { kind: "direct", id: inbound.To },
|
|
58
|
+
});
|
|
59
|
+
const sessionKey = route.sessionKey ?? inbound.SessionKey;
|
|
60
|
+
inbound.SessionKey = sessionKey;
|
|
61
|
+
const storePath = runtime.session.resolveStorePath(ctx.cfg.session?.store, {
|
|
62
|
+
agentId: route.agentId,
|
|
63
|
+
});
|
|
64
|
+
const finalized = runtime.reply.finalizeInboundContext(inbound);
|
|
65
|
+
await runtime.session.recordInboundSession({
|
|
66
|
+
storePath,
|
|
67
|
+
sessionKey,
|
|
68
|
+
ctx: finalized,
|
|
69
|
+
updateLastRoute: {
|
|
70
|
+
sessionKey: route.mainSessionKey ?? sessionKey,
|
|
71
|
+
channel: "claw-manager-api",
|
|
72
|
+
to: inbound.To,
|
|
73
|
+
accountId: "global",
|
|
74
|
+
},
|
|
75
|
+
onRecordError: (error) => ctx.log?.error?.(`recordInboundSession: ${String(error)}`),
|
|
76
|
+
});
|
|
77
|
+
let replyText = "";
|
|
78
|
+
const { dispatcher, replyOptions, markDispatchIdle } = runtime.reply.createReplyDispatcherWithTyping({
|
|
79
|
+
humanDelay: runtime.reply.resolveHumanDelayConfig(ctx.cfg, route.agentId),
|
|
80
|
+
typingCallbacks: createTypingCallbacks({
|
|
81
|
+
start: async () => { },
|
|
82
|
+
stop: async () => { },
|
|
83
|
+
onStartError: () => { },
|
|
84
|
+
onStopError: () => { },
|
|
85
|
+
}),
|
|
86
|
+
deliver: async (payload) => {
|
|
87
|
+
replyText += payload.text ?? "";
|
|
88
|
+
},
|
|
89
|
+
onError: (error) => {
|
|
90
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
try {
|
|
94
|
+
await runtime.reply.withReplyDispatcher({
|
|
95
|
+
dispatcher,
|
|
96
|
+
run: () => runtime.reply.dispatchReplyFromConfig({
|
|
97
|
+
ctx: finalized,
|
|
98
|
+
cfg: ctx.cfg,
|
|
99
|
+
dispatcher,
|
|
100
|
+
replyOptions: {
|
|
101
|
+
...replyOptions,
|
|
102
|
+
disableBlockStreaming: true,
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
markDispatchIdle();
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
channel: "claw-manager-api",
|
|
112
|
+
messageId: trim(ctx.requestId) || randomUUID(),
|
|
113
|
+
text: replyText,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
export const apiChannelPlugin = {
|
|
117
|
+
id: "claw-manager-api",
|
|
118
|
+
meta: {
|
|
119
|
+
id: "claw-manager-api",
|
|
120
|
+
label: "claw-manager-api",
|
|
121
|
+
selectionLabel: "Claw Manager API",
|
|
122
|
+
docsPath: "/channels/claw-manager-api",
|
|
123
|
+
docsLabel: "claw-manager-api",
|
|
124
|
+
blurb: "External API channel.",
|
|
125
|
+
order: 80,
|
|
126
|
+
},
|
|
127
|
+
configSchema: {
|
|
128
|
+
schema: {
|
|
129
|
+
type: "object",
|
|
130
|
+
additionalProperties: true,
|
|
131
|
+
properties: {},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
capabilities: {
|
|
135
|
+
chatTypes: ["direct"],
|
|
136
|
+
media: false,
|
|
137
|
+
blockStreaming: true,
|
|
138
|
+
},
|
|
139
|
+
config: {
|
|
140
|
+
listAccountIds: () => ["global"],
|
|
141
|
+
resolveAccount: () => ({}),
|
|
142
|
+
isConfigured: () => true,
|
|
143
|
+
describeAccount: () => ({
|
|
144
|
+
accountId: "global",
|
|
145
|
+
name: "Claw Manager API",
|
|
146
|
+
enabled: true,
|
|
147
|
+
configured: true,
|
|
148
|
+
}),
|
|
149
|
+
},
|
|
150
|
+
outbound: {
|
|
151
|
+
deliveryMode: "direct",
|
|
152
|
+
textChunkLimit: 8000,
|
|
153
|
+
sendText: async (ctx) => ({
|
|
154
|
+
channel: "claw-manager-api",
|
|
155
|
+
messageId: randomUUID(),
|
|
156
|
+
text: ctx.text ?? "",
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
status: {
|
|
160
|
+
defaultRuntime: {
|
|
161
|
+
accountId: "global",
|
|
162
|
+
lastError: null,
|
|
163
|
+
lastInboundAt: null,
|
|
164
|
+
lastOutboundAt: null,
|
|
165
|
+
},
|
|
166
|
+
collectStatusIssues: () => [],
|
|
167
|
+
buildChannelSummary: ({ snapshot }) => ({
|
|
168
|
+
configured: true,
|
|
169
|
+
lastError: snapshot.lastError ?? null,
|
|
170
|
+
lastInboundAt: snapshot.lastInboundAt ?? null,
|
|
171
|
+
lastOutboundAt: snapshot.lastOutboundAt ?? null,
|
|
172
|
+
}),
|
|
173
|
+
buildAccountSnapshot: ({ runtime }) => ({
|
|
174
|
+
...runtime,
|
|
175
|
+
accountId: "global",
|
|
176
|
+
name: "Claw Manager API",
|
|
177
|
+
enabled: true,
|
|
178
|
+
configured: true,
|
|
179
|
+
}),
|
|
180
|
+
},
|
|
181
|
+
gateway: {
|
|
182
|
+
sendMessage: async (ctx) => dispatchApiMessage(ctx),
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
function trim(value) {
|
|
186
|
+
return typeof value === "string" ? value.trim() : "";
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"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"}
|
package/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
|
+
|
|
3
|
+
import { apiChannelPlugin } from "./src/channel.js";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
id: "claw-manager-api",
|
|
7
|
+
name: "Claw Manager API",
|
|
8
|
+
description: "External API channel for Claw Manager",
|
|
9
|
+
register(api: OpenClawPluginApi) {
|
|
10
|
+
api.registerChannel({ plugin: apiChannelPlugin });
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "claw-manager-api",
|
|
3
|
+
"version": "2026.6.27",
|
|
4
|
+
"channels": [
|
|
5
|
+
"claw-manager-api"
|
|
6
|
+
],
|
|
7
|
+
"channelConfigs": {
|
|
8
|
+
"claw-manager-api": {
|
|
9
|
+
"schema": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"additionalProperties": true
|
|
12
|
+
},
|
|
13
|
+
"label": "claw-manager-api",
|
|
14
|
+
"description": "Claw Manager external API channel configuration."
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"configSchema": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"properties": {}
|
|
21
|
+
}
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@claw-manager/openclaw-api-channel",
|
|
3
|
+
"version": "2026.6.27",
|
|
4
|
+
"description": "OpenClaw API channel for Claw Manager",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/",
|
|
9
|
+
"!src/**/*.test.ts",
|
|
10
|
+
"index.ts",
|
|
11
|
+
"openclaw.plugin.json",
|
|
12
|
+
"dist/",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
19
|
+
"build": "npm run clean && tsc",
|
|
20
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"openclaw": ">=2026.5.12"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@vitest/coverage-v8": "^3.1.0",
|
|
30
|
+
"openclaw": "2026.5.12",
|
|
31
|
+
"typescript": "^5.8.0",
|
|
32
|
+
"vitest": "^3.1.0"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+ssh://git@github.com/zhangsen540445123/claw-manager.git",
|
|
37
|
+
"directory": "plugins/openclaw-api-channel-plugin"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"registry": "https://registry.npmjs.org/"
|
|
42
|
+
},
|
|
43
|
+
"openclaw": {
|
|
44
|
+
"extensions": [
|
|
45
|
+
"./index.ts"
|
|
46
|
+
],
|
|
47
|
+
"runtimeExtensions": [
|
|
48
|
+
"./dist/index.js"
|
|
49
|
+
],
|
|
50
|
+
"channel": {
|
|
51
|
+
"id": "claw-manager-api",
|
|
52
|
+
"label": "claw-manager-api",
|
|
53
|
+
"selectionLabel": "Claw Manager API",
|
|
54
|
+
"docsPath": "/channels/claw-manager-api",
|
|
55
|
+
"docsLabel": "claw-manager-api",
|
|
56
|
+
"blurb": "External API channel",
|
|
57
|
+
"order": 80
|
|
58
|
+
},
|
|
59
|
+
"install": {
|
|
60
|
+
"npmSpec": "@claw-manager/openclaw-api-channel",
|
|
61
|
+
"defaultChoice": "npm",
|
|
62
|
+
"minHostVersion": ">=2026.5.12"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
package/src/channel.ts
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime";
|
|
4
|
+
import type { ChannelPlugin, OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk/core";
|
|
5
|
+
|
|
6
|
+
export type ApiSendMessageParams = {
|
|
7
|
+
requestId?: string;
|
|
8
|
+
openVikingUserId?: string;
|
|
9
|
+
openvikingUserId?: string;
|
|
10
|
+
senderHash?: string;
|
|
11
|
+
senderId?: string;
|
|
12
|
+
conversationId?: string;
|
|
13
|
+
conversationHash?: string;
|
|
14
|
+
message?: string;
|
|
15
|
+
metadata?: Record<string, unknown>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ApiMsgContext = {
|
|
19
|
+
Body: string;
|
|
20
|
+
Text: string;
|
|
21
|
+
From: string;
|
|
22
|
+
To: string;
|
|
23
|
+
AccountId: string;
|
|
24
|
+
OriginatingChannel: "claw-manager-api";
|
|
25
|
+
OriginatingTo: string;
|
|
26
|
+
MessageSid: string;
|
|
27
|
+
Timestamp: number;
|
|
28
|
+
Provider: "claw-manager-api";
|
|
29
|
+
ChatType: "direct";
|
|
30
|
+
SessionKey?: string;
|
|
31
|
+
SenderId: string;
|
|
32
|
+
senderId: string;
|
|
33
|
+
requesterSenderId: string;
|
|
34
|
+
openVikingUserId: string;
|
|
35
|
+
openvikingUserId: string;
|
|
36
|
+
Metadata?: Record<string, unknown>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type GatewaySendMessageContext = ApiSendMessageParams & {
|
|
40
|
+
cfg?: OpenClawConfig;
|
|
41
|
+
channelRuntime?: PluginRuntime["channel"];
|
|
42
|
+
log?: { info?: (message: string) => void; error?: (message: string) => void };
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export function buildApiInboundContext(params: ApiSendMessageParams): ApiMsgContext {
|
|
46
|
+
const message = trim(params.message);
|
|
47
|
+
const openVikingUserId = trim(params.openVikingUserId) || trim(params.openvikingUserId);
|
|
48
|
+
const senderHash = trim(params.senderHash);
|
|
49
|
+
const senderId = trim(params.senderId) || (senderHash ? `api:${senderHash}` : "");
|
|
50
|
+
const conversationHash = trim(params.conversationHash);
|
|
51
|
+
if (!message) {
|
|
52
|
+
throw new Error("message is required");
|
|
53
|
+
}
|
|
54
|
+
if (!openVikingUserId) {
|
|
55
|
+
throw new Error("openVikingUserId is required");
|
|
56
|
+
}
|
|
57
|
+
if (!senderHash) {
|
|
58
|
+
throw new Error("senderHash is required");
|
|
59
|
+
}
|
|
60
|
+
if (!conversationHash) {
|
|
61
|
+
throw new Error("conversationHash is required");
|
|
62
|
+
}
|
|
63
|
+
const from = `api:${senderHash}`;
|
|
64
|
+
const to = `api:${senderHash}:${conversationHash}`;
|
|
65
|
+
return {
|
|
66
|
+
Body: message,
|
|
67
|
+
Text: message,
|
|
68
|
+
From: from,
|
|
69
|
+
To: to,
|
|
70
|
+
AccountId: "global",
|
|
71
|
+
OriginatingChannel: "claw-manager-api",
|
|
72
|
+
OriginatingTo: to,
|
|
73
|
+
MessageSid: `claw-manager-api-${randomUUID()}`,
|
|
74
|
+
Timestamp: Date.now(),
|
|
75
|
+
Provider: "claw-manager-api",
|
|
76
|
+
ChatType: "direct",
|
|
77
|
+
SessionKey: `api:${senderHash}:${conversationHash}`,
|
|
78
|
+
SenderId: senderId,
|
|
79
|
+
senderId,
|
|
80
|
+
requesterSenderId: senderId,
|
|
81
|
+
openVikingUserId,
|
|
82
|
+
openvikingUserId: openVikingUserId,
|
|
83
|
+
Metadata: params.metadata ?? {},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function dispatchApiMessage(ctx: GatewaySendMessageContext): Promise<{ channel: string; messageId: string; text: string }> {
|
|
88
|
+
if (!ctx.channelRuntime) {
|
|
89
|
+
throw new Error("ctx.channelRuntime missing");
|
|
90
|
+
}
|
|
91
|
+
if (!ctx.cfg) {
|
|
92
|
+
throw new Error("ctx.cfg missing");
|
|
93
|
+
}
|
|
94
|
+
const runtime = ctx.channelRuntime;
|
|
95
|
+
const inbound = buildApiInboundContext(ctx);
|
|
96
|
+
const route = runtime.routing.resolveAgentRoute({
|
|
97
|
+
cfg: ctx.cfg,
|
|
98
|
+
channel: "claw-manager-api",
|
|
99
|
+
accountId: "global",
|
|
100
|
+
peer: { kind: "direct", id: inbound.To },
|
|
101
|
+
});
|
|
102
|
+
const sessionKey = route.sessionKey ?? inbound.SessionKey;
|
|
103
|
+
inbound.SessionKey = sessionKey;
|
|
104
|
+
const storePath = runtime.session.resolveStorePath(ctx.cfg.session?.store, {
|
|
105
|
+
agentId: route.agentId,
|
|
106
|
+
});
|
|
107
|
+
const finalized = runtime.reply.finalizeInboundContext(
|
|
108
|
+
inbound as Parameters<typeof runtime.reply.finalizeInboundContext>[0],
|
|
109
|
+
) as unknown as ApiMsgContext & { CommandAuthorized: boolean };
|
|
110
|
+
await runtime.session.recordInboundSession({
|
|
111
|
+
storePath,
|
|
112
|
+
sessionKey,
|
|
113
|
+
ctx: finalized as Parameters<typeof runtime.session.recordInboundSession>[0]["ctx"],
|
|
114
|
+
updateLastRoute: {
|
|
115
|
+
sessionKey: route.mainSessionKey ?? sessionKey,
|
|
116
|
+
channel: "claw-manager-api",
|
|
117
|
+
to: inbound.To,
|
|
118
|
+
accountId: "global",
|
|
119
|
+
},
|
|
120
|
+
onRecordError: (error: unknown) => ctx.log?.error?.(`recordInboundSession: ${String(error)}`),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
let replyText = "";
|
|
124
|
+
const { dispatcher, replyOptions, markDispatchIdle } = runtime.reply.createReplyDispatcherWithTyping({
|
|
125
|
+
humanDelay: runtime.reply.resolveHumanDelayConfig(ctx.cfg, route.agentId),
|
|
126
|
+
typingCallbacks: createTypingCallbacks({
|
|
127
|
+
start: async () => {},
|
|
128
|
+
stop: async () => {},
|
|
129
|
+
onStartError: () => {},
|
|
130
|
+
onStopError: () => {},
|
|
131
|
+
}),
|
|
132
|
+
deliver: async (payload: { text?: string }) => {
|
|
133
|
+
replyText += payload.text ?? "";
|
|
134
|
+
},
|
|
135
|
+
onError: (error: unknown) => {
|
|
136
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
await runtime.reply.withReplyDispatcher({
|
|
142
|
+
dispatcher,
|
|
143
|
+
run: () =>
|
|
144
|
+
runtime.reply.dispatchReplyFromConfig({
|
|
145
|
+
ctx: finalized,
|
|
146
|
+
cfg: ctx.cfg!,
|
|
147
|
+
dispatcher,
|
|
148
|
+
replyOptions: {
|
|
149
|
+
...replyOptions,
|
|
150
|
+
disableBlockStreaming: true,
|
|
151
|
+
},
|
|
152
|
+
}),
|
|
153
|
+
});
|
|
154
|
+
} finally {
|
|
155
|
+
markDispatchIdle();
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
channel: "claw-manager-api",
|
|
159
|
+
messageId: trim(ctx.requestId) || randomUUID(),
|
|
160
|
+
text: replyText,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const apiChannelPlugin: ChannelPlugin<Record<string, never>> = {
|
|
165
|
+
id: "claw-manager-api",
|
|
166
|
+
meta: {
|
|
167
|
+
id: "claw-manager-api",
|
|
168
|
+
label: "claw-manager-api",
|
|
169
|
+
selectionLabel: "Claw Manager API",
|
|
170
|
+
docsPath: "/channels/claw-manager-api",
|
|
171
|
+
docsLabel: "claw-manager-api",
|
|
172
|
+
blurb: "External API channel.",
|
|
173
|
+
order: 80,
|
|
174
|
+
},
|
|
175
|
+
configSchema: {
|
|
176
|
+
schema: {
|
|
177
|
+
type: "object",
|
|
178
|
+
additionalProperties: true,
|
|
179
|
+
properties: {},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
capabilities: {
|
|
183
|
+
chatTypes: ["direct"],
|
|
184
|
+
media: false,
|
|
185
|
+
blockStreaming: true,
|
|
186
|
+
},
|
|
187
|
+
config: {
|
|
188
|
+
listAccountIds: () => ["global"],
|
|
189
|
+
resolveAccount: () => ({}),
|
|
190
|
+
isConfigured: () => true,
|
|
191
|
+
describeAccount: () => ({
|
|
192
|
+
accountId: "global",
|
|
193
|
+
name: "Claw Manager API",
|
|
194
|
+
enabled: true,
|
|
195
|
+
configured: true,
|
|
196
|
+
}),
|
|
197
|
+
},
|
|
198
|
+
outbound: {
|
|
199
|
+
deliveryMode: "direct",
|
|
200
|
+
textChunkLimit: 8000,
|
|
201
|
+
sendText: async (ctx: { text?: string }) => ({
|
|
202
|
+
channel: "claw-manager-api",
|
|
203
|
+
messageId: randomUUID(),
|
|
204
|
+
text: ctx.text ?? "",
|
|
205
|
+
}),
|
|
206
|
+
},
|
|
207
|
+
status: {
|
|
208
|
+
defaultRuntime: {
|
|
209
|
+
accountId: "global",
|
|
210
|
+
lastError: null,
|
|
211
|
+
lastInboundAt: null,
|
|
212
|
+
lastOutboundAt: null,
|
|
213
|
+
},
|
|
214
|
+
collectStatusIssues: () => [],
|
|
215
|
+
buildChannelSummary: ({ snapshot }: { snapshot: Record<string, unknown> }) => ({
|
|
216
|
+
configured: true,
|
|
217
|
+
lastError: snapshot.lastError ?? null,
|
|
218
|
+
lastInboundAt: snapshot.lastInboundAt ?? null,
|
|
219
|
+
lastOutboundAt: snapshot.lastOutboundAt ?? null,
|
|
220
|
+
}),
|
|
221
|
+
buildAccountSnapshot: ({ runtime }: { runtime: Record<string, unknown> }) => ({
|
|
222
|
+
...runtime,
|
|
223
|
+
accountId: "global",
|
|
224
|
+
name: "Claw Manager API",
|
|
225
|
+
enabled: true,
|
|
226
|
+
configured: true,
|
|
227
|
+
}),
|
|
228
|
+
},
|
|
229
|
+
gateway: {
|
|
230
|
+
sendMessage: async (ctx: GatewaySendMessageContext) => dispatchApiMessage(ctx),
|
|
231
|
+
},
|
|
232
|
+
} as unknown as ChannelPlugin<Record<string, never>>;
|
|
233
|
+
|
|
234
|
+
function trim(value: unknown): string {
|
|
235
|
+
return typeof value === "string" ? value.trim() : "";
|
|
236
|
+
}
|