@cydm/happy-elves 0.1.0-beta.306 → 0.1.0-beta.308
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/apps/cli/dist/commands/gateway.js +19 -0
- package/apps/cli/dist/commands/lib/usage.js +2 -0
- package/apps/cli/package.json +1 -1
- package/apps/daemon/dist/gateway/handler.js +27 -1
- package/apps/daemon/dist/gateway/runtime.d.ts +5 -0
- package/apps/daemon/dist/gateway/runtime.js +70 -7
- package/apps/daemon/dist/gateway/store.d.ts +3 -3
- package/apps/daemon/package.json +1 -1
- package/package.json +1 -1
- package/packages/client/dist/types.d.ts +1 -1
- package/packages/shared/dist/protocol-schemas.d.ts +11 -6
- package/packages/shared/dist/protocol-schemas.js +6 -4
- package/packages/shared/dist/protocol-types.d.ts +6 -4
- package/packages/shared/dist/protocol.d.ts +2 -2
- package/packages/shared/dist/protocol.js +2 -2
|
@@ -118,6 +118,25 @@ export async function handleGateway({ domain, action, positional, flags }) {
|
|
|
118
118
|
ok("gateway.test", result);
|
|
119
119
|
return true;
|
|
120
120
|
}
|
|
121
|
+
if (action === "notify") {
|
|
122
|
+
const config = await readConfig(flags);
|
|
123
|
+
const client = new ControllerClient(config);
|
|
124
|
+
const machineId = await resolveGatewayMachineId(client, flags);
|
|
125
|
+
const channelId = gatewayChannelId(flags, positional[0], "lark");
|
|
126
|
+
const externalConversationId = requireString(flags, "conversation");
|
|
127
|
+
const externalMessageId = typeof flags["message-id"] === "string" ? flags["message-id"] : `notify_${Date.now()}`;
|
|
128
|
+
const text = requireString(flags, "text");
|
|
129
|
+
const result = await client.gateway({
|
|
130
|
+
machineId,
|
|
131
|
+
action: "notify",
|
|
132
|
+
channelId,
|
|
133
|
+
externalConversationId,
|
|
134
|
+
externalMessageId,
|
|
135
|
+
text,
|
|
136
|
+
});
|
|
137
|
+
ok("gateway.notify", result);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
121
140
|
if (action === "serve") {
|
|
122
141
|
const config = await readConfig(flags);
|
|
123
142
|
const port = Number(typeof flags.port === "string" ? flags.port : "8789");
|
|
@@ -119,6 +119,7 @@ session stars, recent sessions, pinned workspaces, and current project defaults.
|
|
|
119
119
|
happy-elves gateway disable [<channelId>] [--machine <machineId>] --json
|
|
120
120
|
happy-elves gateway status [--machine <machineId>] [--include-debug] [--json]
|
|
121
121
|
happy-elves gateway test [<channelId>] [--machine <machineId>] --conversation <externalConversationId> --message-id <externalMessageId> --text <prompt> --json
|
|
122
|
+
happy-elves gateway notify [<channelId>] [--machine <machineId>] --conversation <externalConversationId> [--message-id <id>] --text <message> --json
|
|
122
123
|
happy-elves gateway serve [--host 127.0.0.1] [--port 8789] --json # debug only
|
|
123
124
|
|
|
124
125
|
Gateway v1 official Feishu/Lark path is daemon-backed SDK long connection.
|
|
@@ -253,6 +254,7 @@ Core commands:
|
|
|
253
254
|
gateway status --json
|
|
254
255
|
gateway enable --channel fake --machine <machineId> --cwd <cwd> --json # debug only
|
|
255
256
|
gateway test --conversation <id> --message-id <id> --text <prompt> --json
|
|
257
|
+
gateway notify --conversation <id> --text <message> --json
|
|
256
258
|
|
|
257
259
|
memory save --project <key> --text <fact> --json
|
|
258
260
|
memory search --project <key> --query <prompt> --json
|
package/apps/cli/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { decryptJson } from "../../../../packages/shared/dist/index.js";
|
|
2
2
|
import { claimCommandRequest, sendCommandResponse } from "../relay/send.js";
|
|
3
|
-
import { deliverGatewayMessage, publicChannelsForStore, setGatewayLastError, syncGatewayRuntime } from "./runtime.js";
|
|
3
|
+
import { deliverGatewayMessage, notifyGatewayConversation, publicChannelsForStore, setGatewayLastError, syncGatewayRuntime } from "./runtime.js";
|
|
4
4
|
import { readGatewayStore, updateGatewayStore, upsertGatewayChannel } from "./store.js";
|
|
5
5
|
export async function handleGatewayCommand(ws, config, command) {
|
|
6
6
|
if (!claimCommandRequest(ws, command.requestId))
|
|
@@ -86,6 +86,32 @@ async function executeGatewayCommand(config, command) {
|
|
|
86
86
|
throw error;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
if (command.action === "notify") {
|
|
90
|
+
const store = await readGatewayStore();
|
|
91
|
+
const channel = requireChannel(store, command.channelId);
|
|
92
|
+
if (!channel.enabled)
|
|
93
|
+
throw new Error("Gateway channel is disabled");
|
|
94
|
+
if (!command.externalConversationId || !command.externalMessageId || !command.text) {
|
|
95
|
+
throw new Error("gateway notify requires externalConversationId, externalMessageId, and text");
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const delivery = await notifyGatewayConversation(channel, {
|
|
99
|
+
externalConversationId: command.externalConversationId,
|
|
100
|
+
externalMessageId: command.externalMessageId,
|
|
101
|
+
text: command.text,
|
|
102
|
+
});
|
|
103
|
+
const nextStore = await readGatewayStore();
|
|
104
|
+
return {
|
|
105
|
+
action: "notify",
|
|
106
|
+
channel: publicChannelsForStore(nextStore).find((item) => item.id === channel.id),
|
|
107
|
+
delivery,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
await setGatewayLastError(channel.id, error);
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
89
115
|
throw new Error(`Unsupported gateway action: ${command.action}`);
|
|
90
116
|
}
|
|
91
117
|
async function decryptGatewayChannelInput(config, input) {
|
|
@@ -22,6 +22,11 @@ export declare function startGatewayRuntime(config: DaemonConfig): Promise<void>
|
|
|
22
22
|
export declare function stopGatewayRuntime(): Promise<void>;
|
|
23
23
|
export declare function syncGatewayRuntime(config?: DaemonConfig | undefined): Promise<void>;
|
|
24
24
|
export declare function deliverGatewayMessage(config: DaemonConfig, channel: GatewayChannelConfig, message: GatewayInboundMessage): Promise<GatewayDeliveryResult>;
|
|
25
|
+
export declare function notifyGatewayConversation(channel: GatewayChannelConfig, input: {
|
|
26
|
+
externalConversationId: string;
|
|
27
|
+
externalMessageId: string;
|
|
28
|
+
text: string;
|
|
29
|
+
}): Promise<GatewayDeliveryResult>;
|
|
25
30
|
export declare function handleGatewayTurnTerminal(config: DaemonConfig, input: GatewayTerminalInput): Promise<void>;
|
|
26
31
|
export declare function setGatewayLastError(channelId: string, error: unknown): Promise<void>;
|
|
27
32
|
export declare function publicChannelsForStore(store: GatewayStore): import("../../../../packages/shared/dist/index.js").GatewayChannelPublic[];
|
|
@@ -229,6 +229,58 @@ export async function deliverGatewayMessage(config, channel, message) {
|
|
|
229
229
|
senderDisplayName: message.senderDisplayName,
|
|
230
230
|
});
|
|
231
231
|
}
|
|
232
|
+
export async function notifyGatewayConversation(channel, input) {
|
|
233
|
+
if (!channel.enabled)
|
|
234
|
+
throw gatewayError("Gateway channel is disabled", "GATEWAY_DISABLED", 400);
|
|
235
|
+
const adapter = gatewayAdapters.get(channel.id)?.adapter;
|
|
236
|
+
if (!adapter)
|
|
237
|
+
throw gatewayError("Gateway adapter is not listening", "GATEWAY_NOT_LISTENING", 503);
|
|
238
|
+
const destination = destinationFromGatewayConversationId(input.externalConversationId);
|
|
239
|
+
const deliveryId = stableGatewayId("gw_notify", channel.id, input.externalConversationId, input.externalMessageId);
|
|
240
|
+
const result = await adapter.send({
|
|
241
|
+
deliveryId,
|
|
242
|
+
destination,
|
|
243
|
+
payload: {
|
|
244
|
+
type: "notice",
|
|
245
|
+
title: "Happy Elves",
|
|
246
|
+
text: input.text,
|
|
247
|
+
severity: "info",
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
const repliedAt = new Date().toISOString();
|
|
251
|
+
const lastReplied = {
|
|
252
|
+
externalConversationId: input.externalConversationId,
|
|
253
|
+
externalMessageId: input.externalMessageId,
|
|
254
|
+
deliveryId,
|
|
255
|
+
platformMessageId: result.platformMessageId,
|
|
256
|
+
at: repliedAt,
|
|
257
|
+
};
|
|
258
|
+
await updateGatewayStore((current) => ({
|
|
259
|
+
...current,
|
|
260
|
+
channels: current.channels.map((item) => item.id === channel.id
|
|
261
|
+
? { ...item, lastError: undefined, lastReplied, updatedAt: repliedAt }
|
|
262
|
+
: item),
|
|
263
|
+
replyHistory: [
|
|
264
|
+
{
|
|
265
|
+
channelId: channel.id,
|
|
266
|
+
externalConversationId: input.externalConversationId,
|
|
267
|
+
externalMessageId: input.externalMessageId,
|
|
268
|
+
deliveryId,
|
|
269
|
+
platformMessageId: result.platformMessageId,
|
|
270
|
+
repliedAt,
|
|
271
|
+
},
|
|
272
|
+
...current.replyHistory.filter((item) => !(item.channelId === channel.id && item.deliveryId === deliveryId)),
|
|
273
|
+
].slice(0, gatewayReplyHistoryLimit),
|
|
274
|
+
}));
|
|
275
|
+
return {
|
|
276
|
+
channelId: channel.id,
|
|
277
|
+
externalConversationId: input.externalConversationId,
|
|
278
|
+
externalMessageId: input.externalMessageId,
|
|
279
|
+
deliveryId,
|
|
280
|
+
platformMessageId: result.platformMessageId,
|
|
281
|
+
dispatch: "delivered",
|
|
282
|
+
};
|
|
283
|
+
}
|
|
232
284
|
export async function handleGatewayTurnTerminal(config, input) {
|
|
233
285
|
await deliverPendingGatewayReply(config, input);
|
|
234
286
|
await drainGatewayQueue(config, input.sessionId);
|
|
@@ -240,16 +292,17 @@ async function admitGatewayPromptWithMappingRecovery(config, channel, mapping, i
|
|
|
240
292
|
catch (error) {
|
|
241
293
|
if (!canRecoverGatewayMapping(channel, error))
|
|
242
294
|
throw error;
|
|
243
|
-
const recovered = await recoverGatewayMapping(config, channel, mapping, input.externalConversationId);
|
|
295
|
+
const recovered = await recoverGatewayMapping(config, channel, mapping, input.externalConversationId, input.requestId);
|
|
244
296
|
return await admitGatewayPromptNow(config, channel, {
|
|
245
297
|
...input,
|
|
246
298
|
sessionId: recovered.sessionId,
|
|
247
299
|
});
|
|
248
300
|
}
|
|
249
301
|
}
|
|
250
|
-
async function recoverGatewayMapping(config, channel, staleMapping, externalConversationId) {
|
|
251
|
-
const createRequestId = stableGatewayId("gw_create", channel.id, externalConversationId);
|
|
252
|
-
const
|
|
302
|
+
async function recoverGatewayMapping(config, channel, staleMapping, externalConversationId, recoverySeed) {
|
|
303
|
+
const createRequestId = stableGatewayId("gw_create", channel.id, externalConversationId, "recover", recoverySeed);
|
|
304
|
+
const sessionId = stableGatewayId("ses_gw", channel.id, externalConversationId, "recover", recoverySeed);
|
|
305
|
+
const mapping = await createGatewayMapping(config, channel, externalConversationId, createRequestId, sessionId);
|
|
253
306
|
if (mapping.sessionId === staleMapping.sessionId)
|
|
254
307
|
return mapping;
|
|
255
308
|
const now = new Date().toISOString();
|
|
@@ -266,9 +319,9 @@ function canRecoverGatewayMapping(channel, error) {
|
|
|
266
319
|
return false;
|
|
267
320
|
if (!channel.targetCwd)
|
|
268
321
|
return false;
|
|
269
|
-
return errorCode(error) === "SESSION_NOT_FOUND";
|
|
322
|
+
return errorCode(error) === "SESSION_NOT_FOUND" || errorCode(error) === "SESSION_CLOSED";
|
|
270
323
|
}
|
|
271
|
-
async function createGatewayMapping(config, channel, externalConversationId, createRequestId) {
|
|
324
|
+
async function createGatewayMapping(config, channel, externalConversationId, createRequestId, recoveredSessionId) {
|
|
272
325
|
if (channel.targetSessionId) {
|
|
273
326
|
const now = new Date().toISOString();
|
|
274
327
|
const mapping = {
|
|
@@ -287,7 +340,7 @@ async function createGatewayMapping(config, channel, externalConversationId, cre
|
|
|
287
340
|
}
|
|
288
341
|
if (!channel.targetCwd)
|
|
289
342
|
throw gatewayError("Gateway channel needs target cwd or target session", "GATEWAY_TARGET_MISSING", 400);
|
|
290
|
-
const sessionId = stableGatewayId("ses_gw", channel.id, externalConversationId);
|
|
343
|
+
const sessionId = recoveredSessionId ?? stableGatewayId("ses_gw", channel.id, externalConversationId);
|
|
291
344
|
const create = await admitMachineCreateSession(config, {
|
|
292
345
|
requestId: createRequestId,
|
|
293
346
|
sessionId,
|
|
@@ -629,6 +682,16 @@ function gatewayConversationId(destination) {
|
|
|
629
682
|
return `${destination.platformChatId}:thread:${destination.contextKey}`;
|
|
630
683
|
return `${destination.platformChatId}:main`;
|
|
631
684
|
}
|
|
685
|
+
function destinationFromGatewayConversationId(externalConversationId) {
|
|
686
|
+
const threadMatch = /^(.+):thread:(.+)$/.exec(externalConversationId);
|
|
687
|
+
if (threadMatch) {
|
|
688
|
+
return { platformChatId: threadMatch[1], contextKind: "thread", contextKey: threadMatch[2] };
|
|
689
|
+
}
|
|
690
|
+
const mainMatch = /^(.+):main$/.exec(externalConversationId);
|
|
691
|
+
if (mainMatch)
|
|
692
|
+
return { platformChatId: mainMatch[1], contextKind: "main" };
|
|
693
|
+
throw gatewayError("Gateway notify requires a conversation id like <chatId>:main or <chatId>:thread:<threadId>", "GATEWAY_CONVERSATION_INVALID", 400);
|
|
694
|
+
}
|
|
632
695
|
function gatewayAdapterKey(channel) {
|
|
633
696
|
return JSON.stringify({
|
|
634
697
|
type: channel.type,
|
|
@@ -70,9 +70,9 @@ type GatewayReplyHistory = {
|
|
|
70
70
|
channelId: string;
|
|
71
71
|
externalConversationId: string;
|
|
72
72
|
externalMessageId: string;
|
|
73
|
-
sessionId
|
|
74
|
-
requestId
|
|
75
|
-
turnId
|
|
73
|
+
sessionId?: string;
|
|
74
|
+
requestId?: string;
|
|
75
|
+
turnId?: string;
|
|
76
76
|
deliveryId: string;
|
|
77
77
|
platformMessageId?: string;
|
|
78
78
|
repliedAt: string;
|
package/apps/daemon/package.json
CHANGED
package/package.json
CHANGED
|
@@ -297,7 +297,7 @@ export type MachineDevExecInput = {
|
|
|
297
297
|
};
|
|
298
298
|
export type GatewayCommandInput = {
|
|
299
299
|
machineId: string;
|
|
300
|
-
action: "list" | "get" | "upsert" | "enable" | "disable" | "test";
|
|
300
|
+
action: "list" | "get" | "upsert" | "enable" | "disable" | "test" | "notify";
|
|
301
301
|
channelId?: string;
|
|
302
302
|
channel?: GatewayChannelInput;
|
|
303
303
|
externalConversationId?: string;
|
|
@@ -552,9 +552,11 @@ export declare const gatewayDeliveryResultSchema: z.ZodObject<{
|
|
|
552
552
|
channelId: z.ZodString;
|
|
553
553
|
externalConversationId: z.ZodString;
|
|
554
554
|
externalMessageId: z.ZodString;
|
|
555
|
-
sessionId: z.ZodString
|
|
556
|
-
requestId: z.ZodString
|
|
557
|
-
turnId: z.ZodString
|
|
555
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
556
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
557
|
+
turnId: z.ZodOptional<z.ZodString>;
|
|
558
|
+
deliveryId: z.ZodOptional<z.ZodString>;
|
|
559
|
+
platformMessageId: z.ZodOptional<z.ZodString>;
|
|
558
560
|
admission: z.ZodOptional<z.ZodEnum<{
|
|
559
561
|
accepted: "accepted";
|
|
560
562
|
replayed: "replayed";
|
|
@@ -574,6 +576,7 @@ export declare const gatewayCommandResultSchema: z.ZodObject<{
|
|
|
574
576
|
enable: "enable";
|
|
575
577
|
disable: "disable";
|
|
576
578
|
test: "test";
|
|
579
|
+
notify: "notify";
|
|
577
580
|
}>;
|
|
578
581
|
channels: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
579
582
|
id: z.ZodString;
|
|
@@ -727,9 +730,11 @@ export declare const gatewayCommandResultSchema: z.ZodObject<{
|
|
|
727
730
|
channelId: z.ZodString;
|
|
728
731
|
externalConversationId: z.ZodString;
|
|
729
732
|
externalMessageId: z.ZodString;
|
|
730
|
-
sessionId: z.ZodString
|
|
731
|
-
requestId: z.ZodString
|
|
732
|
-
turnId: z.ZodString
|
|
733
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
734
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
735
|
+
turnId: z.ZodOptional<z.ZodString>;
|
|
736
|
+
deliveryId: z.ZodOptional<z.ZodString>;
|
|
737
|
+
platformMessageId: z.ZodOptional<z.ZodString>;
|
|
733
738
|
admission: z.ZodOptional<z.ZodEnum<{
|
|
734
739
|
accepted: "accepted";
|
|
735
740
|
replayed: "replayed";
|
|
@@ -281,16 +281,18 @@ export const gatewayDeliveryResultSchema = z.object({
|
|
|
281
281
|
channelId: z.string().min(1),
|
|
282
282
|
externalConversationId: z.string().min(1),
|
|
283
283
|
externalMessageId: z.string().min(1),
|
|
284
|
-
sessionId: z.string().min(1),
|
|
285
|
-
requestId: z.string().min(1),
|
|
286
|
-
turnId: z.string().min(1),
|
|
284
|
+
sessionId: z.string().min(1).optional(),
|
|
285
|
+
requestId: z.string().min(1).optional(),
|
|
286
|
+
turnId: z.string().min(1).optional(),
|
|
287
|
+
deliveryId: z.string().min(1).optional(),
|
|
288
|
+
platformMessageId: z.string().min(1).optional(),
|
|
287
289
|
admission: z.enum(["accepted", "replayed"]).optional(),
|
|
288
290
|
dispatch: z.enum(["queued", "delivered"]).optional(),
|
|
289
291
|
queued: z.boolean().optional(),
|
|
290
292
|
duplicate: z.boolean().optional(),
|
|
291
293
|
});
|
|
292
294
|
export const gatewayCommandResultSchema = z.object({
|
|
293
|
-
action: z.enum(["list", "get", "upsert", "enable", "disable", "test"]),
|
|
295
|
+
action: z.enum(["list", "get", "upsert", "enable", "disable", "test", "notify"]),
|
|
294
296
|
channels: z.array(gatewayChannelPublicSchema).optional(),
|
|
295
297
|
channel: gatewayChannelPublicSchema.optional(),
|
|
296
298
|
delivery: gatewayDeliveryResultSchema.optional(),
|
|
@@ -295,16 +295,18 @@ export type GatewayDeliveryResult = {
|
|
|
295
295
|
channelId: string;
|
|
296
296
|
externalConversationId: string;
|
|
297
297
|
externalMessageId: string;
|
|
298
|
-
sessionId
|
|
299
|
-
requestId
|
|
300
|
-
turnId
|
|
298
|
+
sessionId?: string;
|
|
299
|
+
requestId?: string;
|
|
300
|
+
turnId?: string;
|
|
301
|
+
deliveryId?: string;
|
|
302
|
+
platformMessageId?: string;
|
|
301
303
|
admission?: "accepted" | "replayed";
|
|
302
304
|
dispatch?: "queued" | "delivered";
|
|
303
305
|
queued?: boolean;
|
|
304
306
|
duplicate?: boolean;
|
|
305
307
|
};
|
|
306
308
|
export type GatewayCommandResult = {
|
|
307
|
-
action: "list" | "get" | "upsert" | "enable" | "disable" | "test";
|
|
309
|
+
action: "list" | "get" | "upsert" | "enable" | "disable" | "test" | "notify";
|
|
308
310
|
channels?: GatewayChannelPublic[];
|
|
309
311
|
channel?: GatewayChannelPublic;
|
|
310
312
|
delivery?: GatewayDeliveryResult;
|
|
@@ -85,7 +85,7 @@ export type ControllerClientMessage = {
|
|
|
85
85
|
type: "controller:gateway";
|
|
86
86
|
requestId: string;
|
|
87
87
|
machineId: string;
|
|
88
|
-
action: "list" | "get" | "upsert" | "enable" | "disable" | "test";
|
|
88
|
+
action: "list" | "get" | "upsert" | "enable" | "disable" | "test" | "notify";
|
|
89
89
|
channelId?: string;
|
|
90
90
|
channel?: GatewayChannelInput;
|
|
91
91
|
externalConversationId?: string;
|
|
@@ -398,7 +398,7 @@ export type MachineCommand = {
|
|
|
398
398
|
type: "machine:gateway";
|
|
399
399
|
requestId: string;
|
|
400
400
|
machineId: string;
|
|
401
|
-
action: "list" | "get" | "upsert" | "enable" | "disable" | "test";
|
|
401
|
+
action: "list" | "get" | "upsert" | "enable" | "disable" | "test" | "notify";
|
|
402
402
|
channelId?: string;
|
|
403
403
|
channel?: GatewayChannelInput;
|
|
404
404
|
externalConversationId?: string;
|
|
@@ -97,7 +97,7 @@ const controllerMessageSchema = z.discriminatedUnion("type", [
|
|
|
97
97
|
type: z.literal("controller:gateway"),
|
|
98
98
|
requestId: z.string().min(1),
|
|
99
99
|
machineId: z.string().min(1),
|
|
100
|
-
action: z.enum(["list", "get", "upsert", "enable", "disable", "test"]),
|
|
100
|
+
action: z.enum(["list", "get", "upsert", "enable", "disable", "test", "notify"]),
|
|
101
101
|
channelId: z.string().min(1).optional(),
|
|
102
102
|
channel: gatewayChannelInputSchema.optional(),
|
|
103
103
|
externalConversationId: z.string().min(1).optional(),
|
|
@@ -473,7 +473,7 @@ const machineCommandSchema = z.discriminatedUnion("type", [
|
|
|
473
473
|
type: z.literal("machine:gateway"),
|
|
474
474
|
requestId: z.string().min(1),
|
|
475
475
|
machineId: z.string().min(1),
|
|
476
|
-
action: z.enum(["list", "get", "upsert", "enable", "disable", "test"]),
|
|
476
|
+
action: z.enum(["list", "get", "upsert", "enable", "disable", "test", "notify"]),
|
|
477
477
|
channelId: z.string().min(1).optional(),
|
|
478
478
|
channel: gatewayChannelInputSchema.optional(),
|
|
479
479
|
externalConversationId: z.string().min(1).optional(),
|