@andreprado/agentkit 0.1.0-alpha.10
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 +69 -0
- package/bin/agentkit.mjs +23 -0
- package/docs/guides/add-channel.md +114 -0
- package/docs/guides/add-knowledge.md +134 -0
- package/docs/guides/add-tool.md +342 -0
- package/docs/guides/agentkit-skills-architecture.md +471 -0
- package/docs/guides/channel-security.md +81 -0
- package/docs/guides/channels-implementation-map.md +243 -0
- package/docs/guides/channels-production-handoff.md +102 -0
- package/docs/guides/connect-telegram.md +110 -0
- package/docs/guides/connect-whatsapp-zapster.md +119 -0
- package/docs/guides/create-agent.md +220 -0
- package/docs/guides/prepare-deploy.md +209 -0
- package/docs/guides/run-evals.md +179 -0
- package/docs/guides/security-rules.md +156 -0
- package/docs/guides/use-provider.md +140 -0
- package/docs/llms-full.txt +876 -0
- package/docs/llms.txt +83 -0
- package/docs/portable-deploy-release-checklist.md +41 -0
- package/package.json +47 -0
- package/src/cli/args.ts +36 -0
- package/src/cli/cloud-client.ts +265 -0
- package/src/cli/commands/channels.ts +810 -0
- package/src/cli/commands/knowledge.ts +136 -0
- package/src/cli/constants.ts +4 -0
- package/src/cli/deploy-chat-ui.ts +392 -0
- package/src/cli/deploy-readiness.ts +348 -0
- package/src/cli/flags.ts +162 -0
- package/src/cli/help.ts +184 -0
- package/src/cli/index.ts +1276 -0
- package/src/cli/process.ts +31 -0
- package/src/cloud/artifact.ts +139 -0
- package/src/cloud/client.ts +79 -0
- package/src/cloud/contracts.ts +63 -0
- package/src/cloud/index.ts +3 -0
- package/src/create-project.ts +177 -0
- package/src/index.ts +408 -0
- package/src/providers/index.ts +25 -0
- package/src/providers/pi.ts +286 -0
- package/src/providers/test.ts +133 -0
- package/src/providers/types.ts +34 -0
- package/src/runtime/build.ts +43 -0
- package/src/runtime/channel-buffer.ts +30 -0
- package/src/runtime/channel-test-harness.ts +112 -0
- package/src/runtime/channels/telegram.ts +360 -0
- package/src/runtime/channels/website.ts +132 -0
- package/src/runtime/channels/whatsapp-meta.ts +71 -0
- package/src/runtime/channels/whatsapp-zapster.ts +278 -0
- package/src/runtime/channels.ts +138 -0
- package/src/runtime/chat.ts +218 -0
- package/src/runtime/config.ts +684 -0
- package/src/runtime/conversations.ts +38 -0
- package/src/runtime/core/deploy-state.ts +54 -0
- package/src/runtime/core/manifest.ts +213 -0
- package/src/runtime/core/targets.ts +133 -0
- package/src/runtime/database.ts +256 -0
- package/src/runtime/db-commands.ts +167 -0
- package/src/runtime/deploy-readiness.ts +105 -0
- package/src/runtime/deploy.ts +1 -0
- package/src/runtime/dev-server.ts +1247 -0
- package/src/runtime/docs.ts +36 -0
- package/src/runtime/env.ts +152 -0
- package/src/runtime/errors.ts +13 -0
- package/src/runtime/evals.ts +509 -0
- package/src/runtime/inspect.ts +203 -0
- package/src/runtime/knowledge/chunk.ts +333 -0
- package/src/runtime/knowledge/config.ts +135 -0
- package/src/runtime/knowledge/embeddings.ts +133 -0
- package/src/runtime/knowledge/ingest.ts +521 -0
- package/src/runtime/knowledge/prompt-policy.ts +30 -0
- package/src/runtime/knowledge/retrieve.ts +283 -0
- package/src/runtime/knowledge/schema.ts +56 -0
- package/src/runtime/knowledge/tool.ts +64 -0
- package/src/runtime/knowledge/vector.ts +258 -0
- package/src/runtime/runtime-contract.ts +93 -0
- package/src/runtime/spec.ts +152 -0
- package/src/runtime/sync.ts +144 -0
- package/src/runtime/targets/cloudflare/build.ts +2517 -0
- package/src/runtime/targets/container/build.ts +146 -0
- package/src/runtime/targets/container/server.ts +33 -0
- package/src/runtime/targets/vps/deploy.ts +206 -0
- package/src/runtime/tool-runner.ts +65 -0
- package/src/runtime/tools.ts +470 -0
- package/src/runtime/traces.ts +41 -0
- package/src/storage/sqlite.ts +1118 -0
- package/src/templates/blank.ts +394 -0
- package/src/templates/dentista.ts +1003 -0
- package/src/templates/index.ts +33 -0
- package/src/templates/skills/agentkit-build-agent/SKILL.md +51 -0
- package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md +20 -0
- package/src/templates/skills/agentkit-build-agent/templates/sales-qualifier.instructions.md +17 -0
- package/src/templates/skills/agentkit-build-agent/templates/support-agent.instructions.md +16 -0
- package/src/templates/skills/agentkit-capsule/SKILL.md +62 -0
- package/src/templates/skills/agentkit-capsule/references/docs-router.md +15 -0
- package/src/templates/skills/agentkit-channels/SKILL.md +62 -0
- package/src/templates/skills/agentkit-channels/references/channel-buffering.md +58 -0
- package/src/templates/skills/agentkit-channels/references/channel-debugging.md +41 -0
- package/src/templates/skills/agentkit-channels/references/telegram.md +38 -0
- package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +44 -0
- package/src/templates/skills/agentkit-database/SKILL.md +45 -0
- package/src/templates/skills/agentkit-database/templates/appointments.schema.sql +15 -0
- package/src/templates/skills/agentkit-database/templates/leads.schema.sql +17 -0
- package/src/templates/skills/agentkit-deploy/SKILL.md +44 -0
- package/src/templates/skills/agentkit-evals/SKILL.md +60 -0
- package/src/templates/skills/agentkit-evals/templates/multi-turn.eval.md +22 -0
- package/src/templates/skills/agentkit-evals/templates/no-leak.eval.md +14 -0
- package/src/templates/skills/agentkit-evals/templates/smoke.eval.md +14 -0
- package/src/templates/skills/agentkit-evals/templates/tool-call.eval.md +18 -0
- package/src/templates/skills/agentkit-knowledge/SKILL.md +40 -0
- package/src/templates/skills/agentkit-knowledge/templates/faq.md +14 -0
- package/src/templates/skills/agentkit-knowledge/templates/policies.md +14 -0
- package/src/templates/skills/agentkit-knowledge/templates/prices.csv +3 -0
- package/src/templates/skills/agentkit-prompts/SKILL.md +45 -0
- package/src/templates/skills/agentkit-prompts/templates/knowledge-grounded-faq.instructions.md +11 -0
- package/src/templates/skills/agentkit-provider/SKILL.md +57 -0
- package/src/templates/skills/agentkit-security/SKILL.md +55 -0
- package/src/templates/skills/agentkit-tools/SKILL.md +36 -0
- package/src/templates/skills/agentkit-tools/examples/database-write.tool.md +35 -0
- package/src/templates/skills/agentkit-tools/examples/eval-safe-external-action.tool.md +37 -0
- package/src/templates/skills/agentkit-tools/examples/lookup-order.tool.md +46 -0
- package/src/templates/skills/agentkit-troubleshooting/SKILL.md +52 -0
- package/src/templates/support.ts +401 -0
|
@@ -0,0 +1,810 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { ParsedArgs } from "../args";
|
|
5
|
+
import { cloudFetch, cloudGet, cloudPost, readCloudError } from "../cloud-client";
|
|
6
|
+
import { parseCloudApiUrl } from "../flags";
|
|
7
|
+
import { loadAgentCapsule } from "../../runtime/config";
|
|
8
|
+
import { readLocalDeployStateIfExists, type LocalDeployState } from "../../runtime/core/deploy-state";
|
|
9
|
+
import { loadCapsuleEnv } from "../../runtime/env";
|
|
10
|
+
import type { AgentChannel } from "../../index";
|
|
11
|
+
|
|
12
|
+
type DeployState = LocalDeployState;
|
|
13
|
+
|
|
14
|
+
type CloudChannel = {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
type: "website" | "telegram" | "whatsapp";
|
|
18
|
+
provider: "agentkit" | "telegram" | "zapster" | "meta";
|
|
19
|
+
status: string;
|
|
20
|
+
webhook_url: string;
|
|
21
|
+
required_secrets: Array<{ name: string; status: string }>;
|
|
22
|
+
buffer?: AgentChannel["buffer"];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type CloudDelivery = {
|
|
26
|
+
id: string;
|
|
27
|
+
channel_id: string;
|
|
28
|
+
direction: string;
|
|
29
|
+
status: string;
|
|
30
|
+
provider: {
|
|
31
|
+
event_id?: string;
|
|
32
|
+
};
|
|
33
|
+
received_at: string;
|
|
34
|
+
updated_at?: string;
|
|
35
|
+
error?: {
|
|
36
|
+
code: string;
|
|
37
|
+
message: string;
|
|
38
|
+
};
|
|
39
|
+
events?: Array<{
|
|
40
|
+
state: string;
|
|
41
|
+
message: string;
|
|
42
|
+
created_at: string;
|
|
43
|
+
}>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type ChannelSetupResponse = {
|
|
47
|
+
channel: CloudChannel;
|
|
48
|
+
setup?: {
|
|
49
|
+
provider: "telegram";
|
|
50
|
+
webhook_url: string;
|
|
51
|
+
status: "configured";
|
|
52
|
+
bot_username?: string;
|
|
53
|
+
get_webhook_info?: {
|
|
54
|
+
url: string;
|
|
55
|
+
pending_update_count: number;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type ChannelDoctorReport = {
|
|
61
|
+
channel: CloudChannel;
|
|
62
|
+
checks: Array<{
|
|
63
|
+
name: string;
|
|
64
|
+
status: "ok" | "warn" | "fail" | "unknown";
|
|
65
|
+
message: string;
|
|
66
|
+
fix?: string;
|
|
67
|
+
}>;
|
|
68
|
+
last_delivery: {
|
|
69
|
+
inbound: CloudDelivery | null;
|
|
70
|
+
outbound: CloudDelivery | null;
|
|
71
|
+
};
|
|
72
|
+
probable_error: string | null;
|
|
73
|
+
suggested_fix: string | null;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export async function handleChannelsCommand(args: ParsedArgs): Promise<void> {
|
|
77
|
+
await loadLocalEnvIntoProcess(process.cwd());
|
|
78
|
+
|
|
79
|
+
const [subcommand, first, second] = args.positional;
|
|
80
|
+
|
|
81
|
+
if (subcommand === "list") {
|
|
82
|
+
const deployState = await readDeployStateIfExists(process.cwd());
|
|
83
|
+
|
|
84
|
+
if (deployState) {
|
|
85
|
+
const channels = await cloudGet<{ channels: CloudChannel[] }>(
|
|
86
|
+
parseCloudApiUrl(args.flags.api),
|
|
87
|
+
`/v1/deploys/${encodeURIComponent(deployState.deploy_id)}/channels`,
|
|
88
|
+
);
|
|
89
|
+
printChannelsTable(channels.channels);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const capsule = await loadAgentCapsule(process.cwd());
|
|
94
|
+
printChannelsTable(
|
|
95
|
+
(capsule.config.channels ?? []).map((channel) => ({
|
|
96
|
+
id: "",
|
|
97
|
+
name: channel.name,
|
|
98
|
+
type: channel.type,
|
|
99
|
+
provider: channel.provider,
|
|
100
|
+
status: "local_config",
|
|
101
|
+
webhook_url: "",
|
|
102
|
+
required_secrets: channel.secrets.map((name) => ({ name, status: "missing" })),
|
|
103
|
+
})),
|
|
104
|
+
);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (subcommand === "add") {
|
|
109
|
+
const type = first;
|
|
110
|
+
const name = second;
|
|
111
|
+
|
|
112
|
+
if (!type || !name || (type !== "website" && type !== "telegram" && type !== "whatsapp")) {
|
|
113
|
+
throw new Error("Usage: agentkit channels add <website|telegram|whatsapp> <name> [--provider zapster|meta]");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const response = await createHostedChannel(type, name, args.flags.provider, args.flags.api);
|
|
117
|
+
printChannelStatus(response.channel);
|
|
118
|
+
printSecretRepairHint(response.channel);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (subcommand === "connect") {
|
|
123
|
+
const type = first;
|
|
124
|
+
const name = second;
|
|
125
|
+
|
|
126
|
+
if (!type || !name || (type !== "website" && type !== "telegram" && type !== "whatsapp")) {
|
|
127
|
+
throw new Error("Usage: agentkit channels connect <website|telegram|whatsapp> <name> [--provider zapster|meta]");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const created = await createHostedChannel(type, name, args.flags.provider, args.flags.api);
|
|
131
|
+
let channel = created.channel;
|
|
132
|
+
printChannelStatus(channel);
|
|
133
|
+
printSecretRepairHint(channel);
|
|
134
|
+
|
|
135
|
+
if (hasMissingRequiredSecrets(channel)) {
|
|
136
|
+
console.log("");
|
|
137
|
+
console.log("Connect blocked: set the missing managed secrets, then rerun this same command.");
|
|
138
|
+
console.log("Run: npm run agentkit -- secret sync --from-local");
|
|
139
|
+
process.exitCode = 1;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (channel.type === "telegram") {
|
|
144
|
+
const setup = await applyTelegramWebhook(channel, args.flags.api);
|
|
145
|
+
channel = setup.channel ?? channel;
|
|
146
|
+
console.log("Telegram webhook confirmed.");
|
|
147
|
+
if (setup.setup?.get_webhook_info) {
|
|
148
|
+
console.log(`Telegram pending updates: ${setup.setup.get_webhook_info.pending_update_count}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const smoke = await runChannelSmoke(channel, args.flags.api, args.flags.message);
|
|
152
|
+
console.log(`Smoke: ${smoke.status}${smoke.delivery_id ? ` (${smoke.delivery_id})` : ""}`);
|
|
153
|
+
printTelegramHumanNextStep(channel.name, setup.setup?.bot_username);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (channel.type === "whatsapp") {
|
|
158
|
+
console.log("Smoke: skipped until the provider webhook is configured.");
|
|
159
|
+
console.log(`Next human step: paste ${channel.webhook_url} into ${channel.provider}'s webhook settings.`);
|
|
160
|
+
} else {
|
|
161
|
+
const smoke = await runChannelSmoke(channel, args.flags.api, args.flags.message);
|
|
162
|
+
console.log(`Smoke: ${smoke.status}${smoke.delivery_id ? ` (${smoke.delivery_id})` : ""}`);
|
|
163
|
+
console.log(`Next human step: use ${channel.webhook_url} from your website client.`);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (subcommand === "setup") {
|
|
169
|
+
if (!first) {
|
|
170
|
+
throw new Error("Usage: agentkit channels setup <name> [--apply]");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const channel = await resolveCloudChannelByName(first, args.flags.api);
|
|
174
|
+
printChannelStatus(channel);
|
|
175
|
+
if (channel.type === "telegram") {
|
|
176
|
+
if (args.flags.apply) {
|
|
177
|
+
const setup = await applyTelegramWebhook(channel, args.flags.api);
|
|
178
|
+
console.log("Telegram webhook confirmed.");
|
|
179
|
+
printChannelStatus(setup.channel ?? channel);
|
|
180
|
+
printTelegramHumanNextStep(channel.name, setup.setup?.bot_username);
|
|
181
|
+
} else {
|
|
182
|
+
console.log(`Setup: call Telegram setWebhook with ${channel.webhook_url}`);
|
|
183
|
+
console.log("Use --apply to mutate Telegram webhook settings.");
|
|
184
|
+
}
|
|
185
|
+
} else if (channel.type === "whatsapp") {
|
|
186
|
+
console.log(`Next step: paste this URL into ${channel.provider}'s webhook settings.`);
|
|
187
|
+
} else {
|
|
188
|
+
console.log(`Website endpoint: ${channel.webhook_url}`);
|
|
189
|
+
console.log("Use this endpoint from the AgentKit website client or a signed server-to-server test.");
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (subcommand === "status") {
|
|
195
|
+
if (!first) {
|
|
196
|
+
throw new Error("Usage: agentkit channels status <name>");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const channel = await resolveCloudChannelByName(first, args.flags.api);
|
|
200
|
+
printChannelStatus(channel);
|
|
201
|
+
await printChannelDeliverySummary(channel, args.flags.api);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (subcommand === "doctor") {
|
|
206
|
+
if (!first) {
|
|
207
|
+
throw new Error("Usage: agentkit channels doctor <name>");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const channel = await resolveCloudChannelByName(first, args.flags.api);
|
|
211
|
+
const report = await cloudGet<{ doctor: ChannelDoctorReport }>(
|
|
212
|
+
parseCloudApiUrl(args.flags.api),
|
|
213
|
+
`/v1/channels/${encodeURIComponent(channel.id)}/doctor`,
|
|
214
|
+
);
|
|
215
|
+
printChannelDoctor(report.doctor);
|
|
216
|
+
|
|
217
|
+
if (report.doctor.checks.some((check) => check.status === "fail")) {
|
|
218
|
+
process.exitCode = 1;
|
|
219
|
+
}
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (subcommand === "test") {
|
|
224
|
+
if (!first) {
|
|
225
|
+
throw new Error('Usage: agentkit channels test <name> [--message "hello"] [--fixture <path>]');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const channel = await resolveCloudChannelByName(first, args.flags.api);
|
|
229
|
+
const apiUrl = parseCloudApiUrl(args.flags.api);
|
|
230
|
+
const body = await channelTestBody(channel, args.flags.message, args.flags.fixture);
|
|
231
|
+
const signed = await runServerSignedChannelTest(channel, apiUrl, body);
|
|
232
|
+
const response = signed.response;
|
|
233
|
+
const payload = signed.payload;
|
|
234
|
+
|
|
235
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
236
|
+
if (!response.ok) {
|
|
237
|
+
process.exitCode = 1;
|
|
238
|
+
}
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (subcommand === "deliveries") {
|
|
243
|
+
if (first === "list") {
|
|
244
|
+
if (!second) {
|
|
245
|
+
throw new Error("Usage: agentkit channels deliveries list <name>");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const channel = await resolveCloudChannelByName(second, args.flags.api);
|
|
249
|
+
const response = await cloudGet<{ deliveries: CloudDelivery[] }>(
|
|
250
|
+
parseCloudApiUrl(args.flags.api),
|
|
251
|
+
`/v1/channels/${encodeURIComponent(channel.id)}/deliveries`,
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
if (response.deliveries.length === 0) {
|
|
255
|
+
console.log("No channel deliveries found.");
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
console.log("ID\tCHANNEL\tDIRECTION\tSTATUS\tPROVIDER_EVENT\tRECEIVED");
|
|
260
|
+
for (const delivery of response.deliveries) {
|
|
261
|
+
console.log(
|
|
262
|
+
[
|
|
263
|
+
delivery.id,
|
|
264
|
+
delivery.channel_id,
|
|
265
|
+
delivery.direction,
|
|
266
|
+
delivery.status,
|
|
267
|
+
delivery.provider.event_id ?? "",
|
|
268
|
+
delivery.received_at,
|
|
269
|
+
].join("\t"),
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (first === "show") {
|
|
276
|
+
if (!second) {
|
|
277
|
+
throw new Error("Usage: agentkit channels deliveries show <delivery-id>");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const response = await cloudGet<{ delivery: CloudDelivery }>(
|
|
281
|
+
parseCloudApiUrl(args.flags.api),
|
|
282
|
+
`/v1/channel-deliveries/${encodeURIComponent(second)}`,
|
|
283
|
+
);
|
|
284
|
+
console.log(JSON.stringify(response.delivery, null, 2));
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
throw new Error(
|
|
290
|
+
"Usage: agentkit channels list | add | connect | setup | status | doctor | test | deliveries list | deliveries show",
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async function createHostedChannel(
|
|
295
|
+
type: "website" | "telegram" | "whatsapp",
|
|
296
|
+
name: string,
|
|
297
|
+
providerFlag: string | boolean | undefined,
|
|
298
|
+
apiFlag: string | boolean | undefined,
|
|
299
|
+
): Promise<{ channel: CloudChannel }> {
|
|
300
|
+
const deployState = await readDeployStateRequired(process.cwd());
|
|
301
|
+
const provider = channelProviderForCli(type, providerFlag);
|
|
302
|
+
const localChannel = await readLocalChannelConfig(process.cwd(), type, provider, name);
|
|
303
|
+
const payload = {
|
|
304
|
+
name,
|
|
305
|
+
type,
|
|
306
|
+
provider,
|
|
307
|
+
secrets: localChannel?.secrets ?? defaultChannelSecretsForCli(type, provider),
|
|
308
|
+
...(localChannel?.limits ? { limits: channelLimitsForApi(localChannel.limits) } : {}),
|
|
309
|
+
...(localChannel?.buffer ? { buffer: localChannel.buffer } : {}),
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
return cloudPost<{ channel: CloudChannel }>(
|
|
313
|
+
parseCloudApiUrl(apiFlag),
|
|
314
|
+
`/v1/deploys/${encodeURIComponent(deployState.deploy_id)}/channels`,
|
|
315
|
+
payload,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function runChannelSmoke(
|
|
320
|
+
channel: CloudChannel,
|
|
321
|
+
apiFlag: string | boolean | undefined,
|
|
322
|
+
messageFlag: string | boolean | undefined,
|
|
323
|
+
): Promise<{ status: string; delivery_id?: string }> {
|
|
324
|
+
const body = await channelTestBody(channel, messageFlag, undefined);
|
|
325
|
+
const { response, payload } = await runServerSignedChannelTest(channel, parseCloudApiUrl(apiFlag), body);
|
|
326
|
+
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
throw new Error(readCloudError(payload, response.status));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (isRecord(payload) && typeof payload.status === "string") {
|
|
332
|
+
return {
|
|
333
|
+
status: payload.status,
|
|
334
|
+
...(typeof payload.delivery_id === "string" ? { delivery_id: payload.delivery_id } : {}),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return { status: "unknown" };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function runServerSignedChannelTest(
|
|
342
|
+
channel: CloudChannel,
|
|
343
|
+
apiUrl: string,
|
|
344
|
+
rawBody: string,
|
|
345
|
+
): Promise<{ response: Response; payload: unknown }> {
|
|
346
|
+
const response = await cloudFetch(apiUrl, `/v1/channels/${encodeURIComponent(channel.id)}/test`, {
|
|
347
|
+
method: "POST",
|
|
348
|
+
headers: { "Content-Type": "application/json" },
|
|
349
|
+
body: JSON.stringify({ raw_body: rawBody }),
|
|
350
|
+
});
|
|
351
|
+
const payload = await response.json().catch(() => null);
|
|
352
|
+
|
|
353
|
+
if (!response.ok && isUnsupportedChannelTestRoute(payload)) {
|
|
354
|
+
return runLocallySignedChannelTest(channel, apiUrl, rawBody);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return { response, payload };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async function runLocallySignedChannelTest(
|
|
361
|
+
channel: CloudChannel,
|
|
362
|
+
apiUrl: string,
|
|
363
|
+
rawBody: string,
|
|
364
|
+
): Promise<{ response: Response; payload: unknown }> {
|
|
365
|
+
const webhookUrl = new URL(channel.webhook_url);
|
|
366
|
+
|
|
367
|
+
if (channel.required_secrets.some((secret) => secret.name === "ZAPSTER_WEBHOOK_TOKEN")) {
|
|
368
|
+
webhookUrl.searchParams.set("token", process.env.ZAPSTER_WEBHOOK_TOKEN ?? "");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const path = `${webhookUrl.pathname}${webhookUrl.search}`;
|
|
372
|
+
const headers = channelTestHeaders(channel);
|
|
373
|
+
const response = await cloudFetch(apiUrl, path, {
|
|
374
|
+
method: "POST",
|
|
375
|
+
headers,
|
|
376
|
+
body: rawBody,
|
|
377
|
+
});
|
|
378
|
+
const payload = await response.json().catch(() => null);
|
|
379
|
+
|
|
380
|
+
return { response, payload };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function isUnsupportedChannelTestRoute(payload: unknown): boolean {
|
|
384
|
+
return (
|
|
385
|
+
isRecord(payload) &&
|
|
386
|
+
isRecord(payload.error) &&
|
|
387
|
+
(payload.error.code === "not_found" ||
|
|
388
|
+
payload.error.code === "channel_store_not_configured" ||
|
|
389
|
+
payload.error.code === "channel_delivery_not_found")
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async function applyTelegramWebhook(
|
|
394
|
+
channel: CloudChannel,
|
|
395
|
+
apiFlag: string | boolean | undefined,
|
|
396
|
+
): Promise<ChannelSetupResponse> {
|
|
397
|
+
try {
|
|
398
|
+
return await cloudPost<ChannelSetupResponse>(
|
|
399
|
+
parseCloudApiUrl(apiFlag),
|
|
400
|
+
`/v1/channels/${encodeURIComponent(channel.id)}/setup`,
|
|
401
|
+
{},
|
|
402
|
+
);
|
|
403
|
+
} catch (error) {
|
|
404
|
+
if (!shouldFallbackToLocalTelegramSetup(error)) {
|
|
405
|
+
throw error;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const botToken = process.env.TELEGRAM_BOT_TOKEN;
|
|
410
|
+
const secretToken = process.env.TELEGRAM_WEBHOOK_SECRET;
|
|
411
|
+
|
|
412
|
+
if (!botToken || !secretToken) {
|
|
413
|
+
throw new Error("TELEGRAM_BOT_TOKEN and TELEGRAM_WEBHOOK_SECRET must be set to apply Telegram setup.");
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
let response: Response;
|
|
417
|
+
const apiBaseUrl = telegramApiBaseUrlFromEnv();
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
response = await fetch(new URL(`/bot${botToken}/setWebhook`, apiBaseUrl).href, {
|
|
421
|
+
method: "POST",
|
|
422
|
+
headers: { "Content-Type": "application/json" },
|
|
423
|
+
body: JSON.stringify({
|
|
424
|
+
url: channel.webhook_url,
|
|
425
|
+
secret_token: secretToken,
|
|
426
|
+
allowed_updates: ["message"],
|
|
427
|
+
}),
|
|
428
|
+
});
|
|
429
|
+
} catch {
|
|
430
|
+
throw new Error("Telegram setWebhook request failed before Telegram returned a response.");
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const payload = await response.json().catch(() => ({}));
|
|
434
|
+
|
|
435
|
+
if (!response.ok || !isTelegramOk(payload)) {
|
|
436
|
+
throw new Error(readTelegramSetupError(payload, response.status));
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const webhookInfo = await fetch(new URL(`/bot${botToken}/getWebhookInfo`, apiBaseUrl).href)
|
|
440
|
+
.then((telegramResponse) => telegramResponse.json())
|
|
441
|
+
.catch(() => null);
|
|
442
|
+
const webhookUrl =
|
|
443
|
+
webhookInfo &&
|
|
444
|
+
typeof webhookInfo === "object" &&
|
|
445
|
+
"result" in webhookInfo &&
|
|
446
|
+
webhookInfo.result &&
|
|
447
|
+
typeof webhookInfo.result === "object" &&
|
|
448
|
+
"url" in webhookInfo.result &&
|
|
449
|
+
typeof webhookInfo.result.url === "string"
|
|
450
|
+
? webhookInfo.result.url
|
|
451
|
+
: "";
|
|
452
|
+
|
|
453
|
+
if (webhookUrl !== channel.webhook_url) {
|
|
454
|
+
throw new Error(`Telegram getWebhookInfo returned ${webhookUrl || "no webhook URL"} instead of ${channel.webhook_url}.`);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
channel: {
|
|
459
|
+
...channel,
|
|
460
|
+
status: "connected",
|
|
461
|
+
},
|
|
462
|
+
setup: {
|
|
463
|
+
provider: "telegram",
|
|
464
|
+
webhook_url: channel.webhook_url,
|
|
465
|
+
status: "configured",
|
|
466
|
+
get_webhook_info: {
|
|
467
|
+
url: webhookUrl,
|
|
468
|
+
pending_update_count: 0,
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function shouldFallbackToLocalTelegramSetup(error: unknown): boolean {
|
|
475
|
+
if (!(error instanceof Error)) {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return /Unknown AgentKit Cloud route|does not support channel delivery records yet|does not support channel resources yet/.test(
|
|
480
|
+
error.message,
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function isTelegramOk(payload: unknown): payload is { ok: true } {
|
|
485
|
+
return Boolean(payload && typeof payload === "object" && "ok" in payload && payload.ok === true);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function readTelegramSetupError(payload: unknown, status: number): string {
|
|
489
|
+
if (payload && typeof payload === "object" && "description" in payload && typeof payload.description === "string") {
|
|
490
|
+
return `Telegram setWebhook failed: ${payload.description}`;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return `Telegram setWebhook failed with HTTP ${status}.`;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function telegramApiBaseUrlFromEnv(): string {
|
|
497
|
+
return process.env.AGENTKIT_TELEGRAM_API_BASE_URL ?? "https://api.telegram.org";
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
async function loadLocalEnvIntoProcess(cwd: string): Promise<void> {
|
|
501
|
+
const env = await loadCapsuleEnv(cwd, process.env);
|
|
502
|
+
|
|
503
|
+
for (const [key, value] of Object.entries(env)) {
|
|
504
|
+
if (value !== undefined && process.env[key] === undefined) {
|
|
505
|
+
process.env[key] = value;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function printTelegramHumanNextStep(channelName: string, botUsername: string | undefined): void {
|
|
511
|
+
console.log("");
|
|
512
|
+
console.log("Next human step:");
|
|
513
|
+
console.log(` Open ${botUsername ? `@${botUsername}` : "your Telegram bot"} in Telegram`);
|
|
514
|
+
console.log(" Send /start");
|
|
515
|
+
console.log(' Send "hello"');
|
|
516
|
+
console.log(` Then run: npm run agentkit -- channels deliveries list ${channelName}`);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
520
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async function readDeployStateIfExists(cwd: string): Promise<DeployState | null> {
|
|
524
|
+
return readLocalDeployStateIfExists(cwd);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
async function readDeployStateRequired(cwd: string): Promise<DeployState> {
|
|
528
|
+
const state = await readDeployStateIfExists(cwd);
|
|
529
|
+
|
|
530
|
+
if (!state?.deploy_id) {
|
|
531
|
+
throw new Error("No .agentkit/deploy.json found. Run agentkit deploy before creating hosted channels.");
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return state;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function printChannelsTable(channels: CloudChannel[]): void {
|
|
538
|
+
if (channels.length === 0) {
|
|
539
|
+
console.log("No channels found.");
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
console.log("NAME\tTYPE\tPROVIDER\tSTATUS\tLAST_EVENT");
|
|
544
|
+
for (const channel of channels) {
|
|
545
|
+
console.log([channel.name, channel.type, channel.provider, channel.status, ""].join("\t"));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function printChannelStatus(channel: CloudChannel): void {
|
|
550
|
+
console.log(`Channel: ${channel.name}`);
|
|
551
|
+
if (channel.id) {
|
|
552
|
+
console.log(`ID: ${channel.id}`);
|
|
553
|
+
}
|
|
554
|
+
console.log(`Type: ${channel.type}`);
|
|
555
|
+
console.log(`Provider: ${channel.provider}`);
|
|
556
|
+
console.log(`Status: ${channel.status}`);
|
|
557
|
+
if (channel.webhook_url) {
|
|
558
|
+
console.log(`Webhook URL: ${channel.webhook_url}`);
|
|
559
|
+
}
|
|
560
|
+
console.log("Required secrets:");
|
|
561
|
+
if (channel.required_secrets.length === 0 && defaultChannelSecretsForCli(channel.type, channel.provider).length > 0) {
|
|
562
|
+
console.log(
|
|
563
|
+
` control-plane channel metadata bug: required_secrets is empty for ${channel.type}/${channel.provider}`,
|
|
564
|
+
);
|
|
565
|
+
} else {
|
|
566
|
+
for (const secret of channel.required_secrets) {
|
|
567
|
+
console.log(` ${secret.name}: ${secret.status}`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (channel.buffer) {
|
|
571
|
+
if (channel.buffer.mode === "off") {
|
|
572
|
+
console.log("Buffer: off");
|
|
573
|
+
} else {
|
|
574
|
+
console.log(
|
|
575
|
+
`Buffer: debounce quiet=${channel.buffer.quietWindowMs}ms max_wait=${channel.buffer.maxWaitMs}ms max_messages=${channel.buffer.maxMessages} max_chars=${channel.buffer.maxChars}`,
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function printSecretRepairHint(channel: CloudChannel): void {
|
|
582
|
+
if (channel.required_secrets.length > 0 || defaultChannelSecretsForCli(channel.type, channel.provider).length === 0) {
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
console.log(
|
|
587
|
+
"Hint: control-plane channel metadata bug. Rerun add/connect against the updated control-plane to repair required_secrets.",
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function hasMissingRequiredSecrets(channel: CloudChannel): boolean {
|
|
592
|
+
const expected = defaultChannelSecretsForCli(channel.type, channel.provider);
|
|
593
|
+
|
|
594
|
+
if (channel.required_secrets.length === 0 && expected.length > 0) {
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return channel.required_secrets.some((secret) => secret.status !== "set");
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
async function printChannelDeliverySummary(
|
|
602
|
+
channel: CloudChannel,
|
|
603
|
+
apiFlag: string | boolean | undefined,
|
|
604
|
+
): Promise<void> {
|
|
605
|
+
const response = await cloudGet<{ deliveries: CloudDelivery[] }>(
|
|
606
|
+
parseCloudApiUrl(apiFlag),
|
|
607
|
+
`/v1/channels/${encodeURIComponent(channel.id)}/deliveries`,
|
|
608
|
+
);
|
|
609
|
+
const inbound = [...response.deliveries].reverse().find((delivery) => delivery.direction === "inbound");
|
|
610
|
+
const outbound = [...response.deliveries].reverse().find((delivery) => delivery.direction === "outbound");
|
|
611
|
+
|
|
612
|
+
console.log("Recent delivery:");
|
|
613
|
+
console.log(` Last inbound: ${inbound ? `${inbound.status} ${inbound.received_at}` : "none"}`);
|
|
614
|
+
console.log(` Last outbound: ${outbound ? `${outbound.status} ${outbound.received_at}` : "none"}`);
|
|
615
|
+
console.log("Provider health: not_checked");
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function printChannelDoctor(report: ChannelDoctorReport): void {
|
|
619
|
+
console.log(`Channel doctor: ${report.channel.name}`);
|
|
620
|
+
console.log("");
|
|
621
|
+
console.log("Checks:");
|
|
622
|
+
for (const check of report.checks) {
|
|
623
|
+
console.log(` ${formatCheckStatus(check.status)} ${check.name}: ${check.message}`);
|
|
624
|
+
if (check.fix) {
|
|
625
|
+
console.log(` Fix: ${check.fix}`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
console.log("");
|
|
630
|
+
console.log("Last delivery:");
|
|
631
|
+
console.log(
|
|
632
|
+
` Inbound: ${report.last_delivery.inbound ? `${report.last_delivery.inbound.status} ${report.last_delivery.inbound.updated_at ?? report.last_delivery.inbound.received_at}` : "none"}`,
|
|
633
|
+
);
|
|
634
|
+
console.log(
|
|
635
|
+
` Outbound: ${report.last_delivery.outbound ? `${report.last_delivery.outbound.status} ${report.last_delivery.outbound.updated_at ?? report.last_delivery.outbound.received_at}` : "none"}`,
|
|
636
|
+
);
|
|
637
|
+
|
|
638
|
+
if (report.probable_error) {
|
|
639
|
+
console.log("");
|
|
640
|
+
console.log(`Probable error: ${report.probable_error}`);
|
|
641
|
+
}
|
|
642
|
+
if (report.suggested_fix) {
|
|
643
|
+
console.log(`Suggested fix: ${report.suggested_fix}`);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function formatCheckStatus(status: ChannelDoctorReport["checks"][number]["status"]): string {
|
|
648
|
+
if (status === "ok") {
|
|
649
|
+
return "OK";
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if (status === "warn") {
|
|
653
|
+
return "WARN";
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
if (status === "fail") {
|
|
657
|
+
return "FAIL";
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
return "UNKNOWN";
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
async function resolveCloudChannelByName(name: string, apiFlag: string | boolean | undefined): Promise<CloudChannel> {
|
|
664
|
+
const deployState = await readDeployStateRequired(process.cwd());
|
|
665
|
+
const response = await cloudGet<{ channels: CloudChannel[] }>(
|
|
666
|
+
parseCloudApiUrl(apiFlag),
|
|
667
|
+
`/v1/deploys/${encodeURIComponent(deployState.deploy_id)}/channels`,
|
|
668
|
+
);
|
|
669
|
+
const channel = response.channels.find((candidate) => candidate.name === name);
|
|
670
|
+
|
|
671
|
+
if (!channel) {
|
|
672
|
+
throw new Error(`Channel "${name}" was not found for deploy ${deployState.deploy_id}.`);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
return channel;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function channelProviderForCli(type: string, providerFlag: string | boolean | undefined): string {
|
|
679
|
+
if (type === "website") {
|
|
680
|
+
return "agentkit";
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (type === "telegram") {
|
|
684
|
+
return "telegram";
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const provider = providerFlag ?? "zapster";
|
|
688
|
+
|
|
689
|
+
if (provider !== "zapster" && provider !== "meta") {
|
|
690
|
+
throw new Error('WhatsApp provider must be "zapster" or "meta".');
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return provider;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function defaultChannelSecretsForCli(type: string, provider: string): string[] {
|
|
697
|
+
if (type === "website") {
|
|
698
|
+
return ["AGENTKIT_WEBSITE_CHANNEL_TOKEN"];
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (type === "telegram") {
|
|
702
|
+
return ["TELEGRAM_BOT_TOKEN", "TELEGRAM_WEBHOOK_SECRET"];
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (type === "whatsapp" && provider === "zapster") {
|
|
706
|
+
return ["ZAPSTER_API_KEY", "ZAPSTER_INSTANCE_ID", "ZAPSTER_WEBHOOK_ID"];
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
if (type === "whatsapp" && provider === "meta") {
|
|
710
|
+
return ["META_WHATSAPP_ACCESS_TOKEN", "META_WHATSAPP_APP_SECRET", "META_WHATSAPP_VERIFY_TOKEN"];
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
return [];
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
async function readLocalChannelConfig(
|
|
717
|
+
cwd: string,
|
|
718
|
+
type: string,
|
|
719
|
+
provider: string,
|
|
720
|
+
name: string,
|
|
721
|
+
): Promise<AgentChannel | null> {
|
|
722
|
+
const capsule = await loadAgentCapsule(cwd);
|
|
723
|
+
return (
|
|
724
|
+
(capsule.config.channels ?? []).find(
|
|
725
|
+
(channel) => channel.name === name && channel.type === type && channel.provider === provider,
|
|
726
|
+
) ?? null
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function channelLimitsForApi(limits: NonNullable<AgentChannel["limits"]>): {
|
|
731
|
+
messages_per_day?: number;
|
|
732
|
+
usd_per_day?: number;
|
|
733
|
+
} {
|
|
734
|
+
return {
|
|
735
|
+
...(limits.messagesPerDay ? { messages_per_day: limits.messagesPerDay } : {}),
|
|
736
|
+
...(limits.usdPerDay ? { usd_per_day: limits.usdPerDay } : {}),
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
async function channelTestBody(
|
|
741
|
+
channel: CloudChannel,
|
|
742
|
+
messageFlag: string | boolean | undefined,
|
|
743
|
+
fixtureFlag: string | boolean | undefined,
|
|
744
|
+
): Promise<string> {
|
|
745
|
+
if (typeof fixtureFlag === "string") {
|
|
746
|
+
return readFile(resolve(process.cwd(), fixtureFlag), "utf8");
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const message = typeof messageFlag === "string" ? messageFlag : "hello";
|
|
750
|
+
|
|
751
|
+
if (channel.type === "telegram") {
|
|
752
|
+
return JSON.stringify({
|
|
753
|
+
update_id: Date.now(),
|
|
754
|
+
message: {
|
|
755
|
+
message_id: 1,
|
|
756
|
+
chat: { id: 456, type: "private" },
|
|
757
|
+
from: { id: 123, first_name: "AgentKit" },
|
|
758
|
+
text: message,
|
|
759
|
+
},
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (channel.type === "whatsapp") {
|
|
764
|
+
return JSON.stringify({
|
|
765
|
+
event_id: `evt_${Date.now()}`,
|
|
766
|
+
instance_id: "local",
|
|
767
|
+
message: {
|
|
768
|
+
id: `msg_${Date.now()}`,
|
|
769
|
+
from: "5511999999999",
|
|
770
|
+
type: "text",
|
|
771
|
+
text: { body: message },
|
|
772
|
+
},
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return JSON.stringify({
|
|
777
|
+
event_id: `web_${Date.now()}`,
|
|
778
|
+
visitor_id: "visitor_test",
|
|
779
|
+
message: {
|
|
780
|
+
id: `msg_${Date.now()}`,
|
|
781
|
+
text: message,
|
|
782
|
+
},
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
function channelTestHeaders(channel: CloudChannel): Headers {
|
|
787
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
788
|
+
|
|
789
|
+
if (channel.type === "website") {
|
|
790
|
+
const token = process.env.AGENTKIT_WEBSITE_CHANNEL_TOKEN;
|
|
791
|
+
|
|
792
|
+
if (token) {
|
|
793
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
if (channel.type === "telegram") {
|
|
798
|
+
headers.set("X-Telegram-Bot-Api-Secret-Token", process.env.TELEGRAM_WEBHOOK_SECRET ?? "");
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (channel.type === "whatsapp" && channel.provider === "zapster") {
|
|
802
|
+
headers.set("X-Instance-ID", process.env.ZAPSTER_INSTANCE_ID ?? "");
|
|
803
|
+
headers.set("X-Webhook-ID", process.env.ZAPSTER_WEBHOOK_ID ?? "");
|
|
804
|
+
headers.set("X-Message-ID", `cli_msg_${Date.now()}`);
|
|
805
|
+
headers.set("X-Attempt-Count", "1");
|
|
806
|
+
headers.set("User-Agent", "Zapsterapi/agentkit-cli");
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
return headers;
|
|
810
|
+
}
|