@andreprado/agentkit 0.1.0-alpha.8 → 0.1.0

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.
Files changed (117) hide show
  1. package/README.md +18 -1
  2. package/docs/guides/add-channel.md +251 -7
  3. package/docs/guides/add-knowledge.md +10 -0
  4. package/docs/guides/add-managed-composio.md +165 -0
  5. package/docs/guides/add-tool.md +10 -3
  6. package/docs/guides/channel-security.md +162 -32
  7. package/docs/guides/connect-discord.md +178 -0
  8. package/docs/guides/connect-slack.md +126 -0
  9. package/docs/guides/connect-telegram.md +61 -1
  10. package/docs/guides/connect-whatsapp-evolution.md +121 -0
  11. package/docs/guides/connect-whatsapp-uazapi.md +139 -0
  12. package/docs/guides/connect-whatsapp-zapster.md +119 -16
  13. package/docs/guides/create-agent.md +31 -4
  14. package/docs/guides/debug-channel.md +159 -0
  15. package/docs/guides/improve-from-production.md +151 -0
  16. package/docs/guides/prepare-deploy.md +32 -14
  17. package/docs/guides/replay-production-traces.md +72 -0
  18. package/docs/guides/run-evals.md +95 -25
  19. package/docs/guides/security-rules.md +9 -5
  20. package/docs/guides/send-feedback.md +135 -0
  21. package/docs/guides/use-jev.md +67 -0
  22. package/docs/guides/use-provider.md +70 -3
  23. package/docs/llms-full.txt +295 -25
  24. package/docs/llms.txt +54 -7
  25. package/package.json +3 -7
  26. package/src/cli/args.ts +23 -2
  27. package/src/cli/cloud-client.ts +121 -9
  28. package/src/cli/commands/channels.ts +1185 -50
  29. package/src/cli/commands/feedback.ts +438 -0
  30. package/src/cli/commands/provider.ts +47 -0
  31. package/src/cli/commands/transcribe.ts +171 -0
  32. package/src/cli/deploy-chat-ui.ts +232 -18
  33. package/src/cli/deploy-readiness.ts +227 -14
  34. package/src/cli/help.ts +68 -8
  35. package/src/cli/index.ts +740 -35
  36. package/src/cli/new-command.ts +41 -0
  37. package/src/cloud/client.ts +4 -3
  38. package/src/cloud/contracts.ts +1 -1
  39. package/src/create-project.ts +18 -35
  40. package/src/index.ts +565 -11
  41. package/src/providers/codex-auth.ts +111 -0
  42. package/src/providers/pi.ts +88 -19
  43. package/src/providers/test.ts +36 -0
  44. package/src/providers/types.ts +8 -0
  45. package/src/runtime/channel-test-harness.ts +21 -1
  46. package/src/runtime/channels/discord.ts +896 -0
  47. package/src/runtime/channels/generic-webhook.ts +974 -0
  48. package/src/runtime/channels/slack.ts +646 -0
  49. package/src/runtime/channels/telegram.ts +466 -23
  50. package/src/runtime/channels/whatsapp-evolution.ts +1357 -0
  51. package/src/runtime/channels/whatsapp-meta.ts +9 -0
  52. package/src/runtime/channels/whatsapp-uazapi.ts +1323 -0
  53. package/src/runtime/channels/whatsapp-zapster.ts +674 -40
  54. package/src/runtime/channels.ts +89 -4
  55. package/src/runtime/chat.ts +70 -44
  56. package/src/runtime/config.ts +489 -20
  57. package/src/runtime/core/manifest.ts +75 -5
  58. package/src/runtime/core/targets.ts +5 -5
  59. package/src/runtime/deploy-readiness.ts +34 -4
  60. package/src/runtime/dev-server.ts +639 -39
  61. package/src/runtime/env.ts +8 -3
  62. package/src/runtime/evals.ts +445 -74
  63. package/src/runtime/improve.ts +868 -0
  64. package/src/runtime/inspect.ts +173 -4
  65. package/src/runtime/integrations/composio.ts +425 -0
  66. package/src/runtime/knowledge/retrieve.ts +25 -5
  67. package/src/runtime/knowledge/schema.ts +45 -1
  68. package/src/runtime/prompt-context.ts +141 -0
  69. package/src/runtime/runtime-contract.ts +71 -7
  70. package/src/runtime/skills.ts +95 -0
  71. package/src/runtime/targets/cloudflare/build.ts +1010 -208
  72. package/src/runtime/targets/container/server.ts +1 -1
  73. package/src/runtime/targets/vps/deploy.ts +26 -9
  74. package/src/runtime/tool-runner.ts +9 -1
  75. package/src/runtime/tools.ts +26 -2
  76. package/src/runtime/transcription.ts +483 -0
  77. package/src/storage/sqlite.ts +7 -2
  78. package/src/templates/blank.ts +37 -9
  79. package/src/templates/dentista.ts +40 -14
  80. package/src/templates/skills/agentkit-build-agent/SKILL.md +34 -5
  81. package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md +2 -1
  82. package/src/templates/skills/agentkit-capsule/SKILL.md +32 -3
  83. package/src/templates/skills/agentkit-capsule/references/docs-router.md +2 -2
  84. package/src/templates/skills/agentkit-channels/SKILL.md +71 -6
  85. package/src/templates/skills/agentkit-channels/references/channel-buffering.md +9 -2
  86. package/src/templates/skills/agentkit-channels/references/channel-debugging.md +34 -5
  87. package/src/templates/skills/agentkit-channels/references/discord.md +93 -0
  88. package/src/templates/skills/agentkit-channels/references/slack.md +56 -0
  89. package/src/templates/skills/agentkit-channels/references/telegram.md +39 -4
  90. package/src/templates/skills/agentkit-channels/references/whatsapp-evolution.md +57 -0
  91. package/src/templates/skills/agentkit-channels/references/whatsapp-uazapi.md +54 -0
  92. package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +42 -8
  93. package/src/templates/skills/agentkit-database/SKILL.md +11 -0
  94. package/src/templates/skills/agentkit-deploy/SKILL.md +9 -1
  95. package/src/templates/skills/agentkit-evals/SKILL.md +77 -13
  96. package/src/templates/skills/agentkit-evals/templates/multi-turn.eval.md +13 -6
  97. package/src/templates/skills/agentkit-evals/templates/no-leak.eval.md +8 -4
  98. package/src/templates/skills/agentkit-evals/templates/smoke.eval.md +8 -4
  99. package/src/templates/skills/agentkit-evals/templates/tool-call.eval.md +16 -7
  100. package/src/templates/skills/agentkit-improve/SKILL.md +96 -0
  101. package/src/templates/skills/agentkit-improve/references/replay-side-effects.md +18 -0
  102. package/src/templates/skills/agentkit-improve/references/trace-packets.md +22 -0
  103. package/src/templates/skills/agentkit-improve/templates/regression.eval.md +18 -0
  104. package/src/templates/skills/agentkit-integrations/SKILL.md +98 -0
  105. package/src/templates/skills/agentkit-knowledge/SKILL.md +4 -1
  106. package/src/templates/skills/agentkit-prompts/SKILL.md +3 -1
  107. package/src/templates/skills/agentkit-provider/SKILL.md +29 -4
  108. package/src/templates/skills/agentkit-security/SKILL.md +5 -2
  109. package/src/templates/skills/agentkit-tools/SKILL.md +8 -1
  110. package/src/templates/skills/agentkit-tools/examples/eval-safe-external-action.tool.md +8 -8
  111. package/src/templates/skills/agentkit-tools/examples/jev-service-fit.tool.md +110 -0
  112. package/src/templates/skills/agentkit-troubleshooting/SKILL.md +25 -1
  113. package/src/templates/support.ts +42 -12
  114. package/docs/guides/agentkit-skills-architecture.md +0 -471
  115. package/docs/guides/channels-implementation-map.md +0 -243
  116. package/docs/guides/channels-production-handoff.md +0 -101
  117. package/docs/portable-deploy-release-checklist.md +0 -41
@@ -0,0 +1,111 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { setTimeout as delay } from "node:timers/promises";
6
+
7
+ import { refreshOpenAICodexToken, type OAuthCredentials } from "@earendil-works/pi-ai/oauth";
8
+
9
+ import { AgentKitError } from "../runtime/errors";
10
+
11
+ export function codexAuthPath(): string {
12
+ return join(homedir(), ".agentkit", "providers", "openai-codex.json");
13
+ }
14
+
15
+ function validateCredentials(value: unknown): OAuthCredentials {
16
+ if (!value || typeof value !== "object" ||
17
+ !("access" in value) || typeof value.access !== "string" || !value.access.trim() ||
18
+ !("refresh" in value) || typeof value.refresh !== "string" || !value.refresh.trim() ||
19
+ !("expires" in value) || typeof value.expires !== "number" || !Number.isFinite(value.expires) || value.expires <= 0) {
20
+ throw new AgentKitError("provider_auth_invalid", "Invalid Codex credentials. Run agentkit provider login openai-codex again.");
21
+ }
22
+ return value as OAuthCredentials;
23
+ }
24
+
25
+ async function readCredentials(path: string): Promise<OAuthCredentials | null> {
26
+ let source: string;
27
+ try {
28
+ source = await readFile(path, "utf8");
29
+ } catch (error) {
30
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
31
+ throw new AgentKitError("provider_auth_unreadable", "Cannot read the local Codex login. Check credential file permissions.");
32
+ }
33
+ try {
34
+ return validateCredentials(JSON.parse(source));
35
+ } catch {
36
+ throw new AgentKitError("provider_auth_invalid", "Invalid Codex credentials. Run agentkit provider login openai-codex again.");
37
+ }
38
+ }
39
+
40
+ async function writeCredentials(path: string, credentials: OAuthCredentials): Promise<void> {
41
+ validateCredentials(credentials);
42
+ const temporary = `${path}.${randomUUID()}.tmp`;
43
+ try {
44
+ await writeFile(temporary, JSON.stringify(credentials), { mode: 0o600, flag: "wx" });
45
+ await rename(temporary, path);
46
+ } finally {
47
+ await rm(temporary, { force: true });
48
+ }
49
+ }
50
+
51
+ async function withAuthLock<T>(path: string, action: () => Promise<T>): Promise<T> {
52
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
53
+ await chmod(dirname(path), 0o700);
54
+ const lock = `${path}.lock`;
55
+ const deadline = Date.now() + 10_000;
56
+ while (true) {
57
+ try {
58
+ await mkdir(lock, { mode: 0o700 });
59
+ break;
60
+ } catch (error) {
61
+ if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
62
+ if (Date.now() >= deadline) {
63
+ throw new AgentKitError("provider_auth_busy", `Codex credentials are busy. Retry; if the previous process crashed, remove ${lock} after stopping AgentKit processes.`);
64
+ }
65
+ await delay(50);
66
+ }
67
+ }
68
+ try {
69
+ return await action();
70
+ } finally {
71
+ await rm(lock, { recursive: true, force: true });
72
+ }
73
+ }
74
+
75
+ export async function saveCodexLogin(credentials: OAuthCredentials, path = codexAuthPath()): Promise<void> {
76
+ await withAuthLock(path, () => writeCredentials(path, credentials));
77
+ }
78
+
79
+ export async function clearCodexLogin(path = codexAuthPath()): Promise<void> {
80
+ await withAuthLock(path, () => rm(path, { force: true }));
81
+ }
82
+
83
+ export async function codexLoginStatus(path = codexAuthPath()) {
84
+ const credentials = await readCredentials(path);
85
+ return {
86
+ provider: "openai-codex",
87
+ status: !credentials ? "logged_out" : credentials.expires <= Date.now() ? "refresh_required" : "logged_in",
88
+ };
89
+ }
90
+
91
+ export async function getCodexApiKey(
92
+ path = codexAuthPath(),
93
+ refresh = refreshOpenAICodexToken,
94
+ ): Promise<string> {
95
+ return withAuthLock(path, async () => {
96
+ const credentials = await readCredentials(path);
97
+ if (!credentials) {
98
+ throw new AgentKitError("provider_auth_required", "Run agentkit provider login openai-codex before using this provider.");
99
+ }
100
+ if (credentials.expires > Date.now() + 60_000) return credentials.access;
101
+ let updated: OAuthCredentials;
102
+ try {
103
+ updated = validateCredentials(await refresh(credentials.refresh));
104
+ } catch {
105
+ // Do not persist or expose provider error bodies containing credentials.
106
+ throw new AgentKitError("provider_auth_refresh_failed", "Could not refresh the Codex login. Run agentkit provider login openai-codex again.");
107
+ }
108
+ await writeCredentials(path, updated);
109
+ return updated.access;
110
+ });
111
+ }
@@ -17,8 +17,11 @@ import type { AgentProviderName, AgentTool } from "../index";
17
17
  import { AgentKitError } from "../runtime/errors";
18
18
  import type { ProviderAdapter, ProviderRunInput, ProviderRunResult } from "./types";
19
19
 
20
- const PI_PROVIDER_NAMES = ["openai", "anthropic", "openrouter"] as const satisfies AgentProviderName[];
20
+ const PI_PROVIDER_NAMES = ["openai", "openai-codex", "anthropic", "openrouter", "opencode", "opencode-go"] as const satisfies AgentProviderName[];
21
21
  const MAX_TOOL_TURNS = 8;
22
+ const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
23
+ const UNKNOWN_OPENROUTER_CONTEXT_WINDOW = 128000;
24
+ const UNKNOWN_OPENROUTER_MAX_TOKENS = 8192;
22
25
 
23
26
  export const piProviderAdapters: ProviderAdapter[] = PI_PROVIDER_NAMES.map((name) => ({
24
27
  name,
@@ -29,7 +32,7 @@ export const piProviderAdapters: ProviderAdapter[] = PI_PROVIDER_NAMES.map((name
29
32
 
30
33
  async function runPiProvider(input: ProviderRunInput): Promise<ProviderRunResult> {
31
34
  const provider = toPiProvider(input.agent.provider.name);
32
- const apiKey = requireProviderApiKey(provider, input.env ?? process.env);
35
+ const apiKey = input.apiKey ?? requireProviderApiKey(provider, input.env ?? process.env);
33
36
  const model = resolveModel(provider, input.agent.provider.model);
34
37
  const messages = toPiMessages(input.messages);
35
38
  const tools = input.tools.map(toPiTool);
@@ -97,7 +100,7 @@ async function runPiProvider(input: ProviderRunInput): Promise<ProviderRunResult
97
100
  content: [
98
101
  {
99
102
  type: "text",
100
- text: result.rendered?.text ?? JSON.stringify(result.output),
103
+ text: providerToolResultText(result),
101
104
  },
102
105
  ],
103
106
  isError: false,
@@ -109,6 +112,19 @@ async function runPiProvider(input: ProviderRunInput): Promise<ProviderRunResult
109
112
  throw new AgentKitError("runtime_error", `Pi provider exceeded ${MAX_TOOL_TURNS} tool turns.`);
110
113
  }
111
114
 
115
+ export function providerToolResultText(result: {
116
+ name: string;
117
+ visibility?: "user" | "internal";
118
+ rendered?: { text?: string };
119
+ output: unknown;
120
+ }): string {
121
+ if (result.visibility === "internal") {
122
+ return `Internal tool ${result.name} completed.`;
123
+ }
124
+
125
+ return result.rendered?.text ?? JSON.stringify(result.output);
126
+ }
127
+
112
128
  async function runPiTurn(
113
129
  model: Model<any>,
114
130
  context: Parameters<typeof stream>[1],
@@ -143,7 +159,14 @@ async function runPiTurn(
143
159
  }
144
160
 
145
161
  function toPiProvider(provider: string): Provider {
146
- if (provider === "openai" || provider === "anthropic" || provider === "openrouter") {
162
+ if (
163
+ provider === "openai" ||
164
+ provider === "openai-codex" ||
165
+ provider === "anthropic" ||
166
+ provider === "openrouter" ||
167
+ provider === "opencode" ||
168
+ provider === "opencode-go"
169
+ ) {
147
170
  return provider;
148
171
  }
149
172
 
@@ -151,6 +174,10 @@ function toPiProvider(provider: string): Provider {
151
174
  }
152
175
 
153
176
  function requireProviderApiKey(provider: Provider, env: Record<string, string | undefined>): string {
177
+ if (provider === "openai-codex") {
178
+ throw new AgentKitError("provider_auth_required", "Run agentkit provider login openai-codex, then use local chat, dev, or eval.");
179
+ }
180
+
154
181
  const envNames = findEnvKeys(provider) ?? defaultProviderSecretNames(provider);
155
182
  const setName = envNames.find((name) => env[name]);
156
183
 
@@ -165,6 +192,10 @@ function requireProviderApiKey(provider: Provider, env: Record<string, string |
165
192
  }
166
193
 
167
194
  function defaultProviderSecretNames(provider: Provider): string[] {
195
+ if (provider === "opencode" || provider === "opencode-go") {
196
+ return ["OPENCODE_API_KEY"];
197
+ }
198
+
168
199
  return [`${provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`];
169
200
  }
170
201
 
@@ -176,25 +207,56 @@ function formatSecretList(names: string[]): string {
176
207
  return `one of: ${names.join(", ")}`;
177
208
  }
178
209
 
179
- function resolveModel(provider: Provider, modelId: string): Model<any> {
180
- const modelExists = getModels(provider as any).some((model) => model.id === modelId);
210
+ export function resolveModel(provider: Provider, modelId: string): Model<any> {
211
+ const model = getModel(provider as any, modelId as any) as Model<any> | undefined;
181
212
 
182
- if (!modelExists) {
183
- throw new AgentKitError(
184
- "provider_model_unsupported",
185
- `Pi SDK could not resolve provider "${provider}" model "${modelId}".`,
186
- );
213
+ if (model) {
214
+ return model;
187
215
  }
188
216
 
189
- try {
190
- return getModel(provider as any, modelId as any) as Model<any>;
191
- } catch (error) {
192
- throw new AgentKitError(
193
- "provider_model_unsupported",
194
- `Pi SDK could not resolve provider "${provider}" model "${modelId}".`,
195
- { cause: error },
196
- );
217
+ if (provider === "openrouter") {
218
+ return createOpenRouterPassThroughModel(modelId);
197
219
  }
220
+
221
+ throw new AgentKitError(
222
+ "provider_model_unsupported",
223
+ `Pi SDK could not resolve provider "${provider}" model "${modelId}". ${knownModelHint(provider)}`,
224
+ );
225
+ }
226
+
227
+ function createOpenRouterPassThroughModel(modelId: string): Model<"openai-completions"> {
228
+ return {
229
+ id: modelId,
230
+ name: `OpenRouter ${modelId}`,
231
+ api: "openai-completions",
232
+ provider: "openrouter",
233
+ baseUrl: OPENROUTER_BASE_URL,
234
+ reasoning: false,
235
+ input: ["text"],
236
+ cost: {
237
+ input: 0,
238
+ output: 0,
239
+ cacheRead: 0,
240
+ cacheWrite: 0,
241
+ },
242
+ contextWindow: UNKNOWN_OPENROUTER_CONTEXT_WINDOW,
243
+ maxTokens: UNKNOWN_OPENROUTER_MAX_TOKENS,
244
+ compat: {
245
+ openRouterRouting: {},
246
+ },
247
+ };
248
+ }
249
+
250
+ function knownModelHint(provider: Provider): string {
251
+ const examples = getModels(provider as any)
252
+ .slice(0, 5)
253
+ .map((model) => model.id);
254
+
255
+ if (examples.length === 0) {
256
+ return "Use a model id supported by the installed Pi SDK for that provider.";
257
+ }
258
+
259
+ return `Use a model id supported by the installed Pi SDK for that provider. Examples: ${examples.join(", ")}.`;
198
260
  }
199
261
 
200
262
  function toPiMessages(messages: ProviderRunInput["messages"]): Message[] {
@@ -244,6 +306,13 @@ function normalizeUsage(usage: Usage | undefined): ProviderRunResult["usage"] |
244
306
  inputTokens: usage.input,
245
307
  outputTokens: usage.output,
246
308
  totalTokens: usage.totalTokens,
309
+ cost: {
310
+ input: usage.cost.input,
311
+ output: usage.cost.output,
312
+ cacheRead: usage.cost.cacheRead,
313
+ cacheWrite: usage.cost.cacheWrite,
314
+ total: usage.cost.total,
315
+ },
247
316
  };
248
317
  }
249
318
 
@@ -37,6 +37,17 @@ export const testProviderAdapter: ProviderAdapter = {
37
37
  };
38
38
  }
39
39
 
40
+ const currentDate = answerCurrentDate(input.instructions, userMessage.content);
41
+
42
+ if (currentDate) {
43
+ return {
44
+ message: {
45
+ role: "assistant",
46
+ content: currentDate,
47
+ },
48
+ };
49
+ }
50
+
40
51
  const rememberedName = answerRememberedName(input.messages);
41
52
 
42
53
  if (rememberedName) {
@@ -95,6 +106,31 @@ function answerRememberedName(messages: AgentMessage[]): string | null {
95
106
  return null;
96
107
  }
97
108
 
109
+ function answerCurrentDate(instructions: string, content: string): string | null {
110
+ if (!/(today|current date|what date|data de hoje|hoje)/i.test(content)) {
111
+ return null;
112
+ }
113
+
114
+ const localDate = readRuntimeContextValue(instructions, "Local date");
115
+
116
+ if (!localDate) {
117
+ return null;
118
+ }
119
+
120
+ const localWeekday = readRuntimeContextValue(instructions, "Local weekday");
121
+ const timeZone = readRuntimeContextValue(instructions, "Time zone");
122
+ const weekday = localWeekday ? ` (${localWeekday})` : "";
123
+ const zone = timeZone ? ` in ${timeZone}` : "";
124
+
125
+ return `Today is ${localDate}${weekday}${zone}.`;
126
+ }
127
+
128
+ function readRuntimeContextValue(instructions: string, label: string): string | null {
129
+ const escapedLabel = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
130
+ const match = instructions.match(new RegExp(`^- ${escapedLabel}: (.+)$`, "m"));
131
+ return match?.[1]?.trim() || null;
132
+ }
133
+
98
134
  function asksForName(content: string): boolean {
99
135
  return /what(?:'s| is) my name\??/i.test(content) || /(como|qual)\s+(é|e)\s*(o\s+)?meu nome\??/i.test(content);
100
136
  }
@@ -15,6 +15,7 @@ export type ProviderRunInput = {
15
15
  tools: AgentTool[];
16
16
  toolRuntime?: ToolRuntime;
17
17
  env?: Record<string, string | undefined>;
18
+ apiKey?: string;
18
19
  signal?: AbortSignal;
19
20
  };
20
21
 
@@ -24,6 +25,13 @@ export type ProviderRunResult = {
24
25
  inputTokens?: number;
25
26
  outputTokens?: number;
26
27
  totalTokens?: number;
28
+ cost?: {
29
+ input?: number;
30
+ output?: number;
31
+ cacheRead?: number;
32
+ cacheWrite?: number;
33
+ total?: number;
34
+ };
27
35
  };
28
36
  raw?: unknown;
29
37
  };
@@ -8,11 +8,31 @@ import type { NormalizedChannelEvent, RawWebhookEvent } from "./channels";
8
8
  export type ChannelFixtureName =
9
9
  | "website-message"
10
10
  | "telegram-message"
11
+ | "telegram-audio-message"
11
12
  | "telegram-duplicate-message"
12
13
  | "telegram-malformed-payload"
13
14
  | "zapster-message"
15
+ | "zapster-audio-message"
14
16
  | "zapster-duplicate-message"
15
- | "zapster-unsupported-media";
17
+ | "zapster-unsupported-media"
18
+ | "uazapi-message"
19
+ | "uazapi-audio-message"
20
+ | "uazapi-duplicate-message"
21
+ | "uazapi-unsupported-media"
22
+ | "uazapi-was-sent-by-api"
23
+ | "evolution-message"
24
+ | "evolution-audio-message"
25
+ | "evolution-captioned-media"
26
+ | "evolution-duplicate-message"
27
+ | "evolution-from-me"
28
+ | "evolution-unsupported-media"
29
+ | "discord-command"
30
+ | "discord-message-create"
31
+ | "discord-ping"
32
+ | "slack-app-mention"
33
+ | "slack-direct-message"
34
+ | "generic-webhook-message"
35
+ | "generic-webhook-duplicate";
16
36
 
17
37
  export type ChannelFixture = {
18
38
  name: ChannelFixtureName;