@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.
- package/README.md +18 -1
- package/docs/guides/add-channel.md +251 -7
- package/docs/guides/add-knowledge.md +10 -0
- package/docs/guides/add-managed-composio.md +165 -0
- package/docs/guides/add-tool.md +10 -3
- package/docs/guides/channel-security.md +162 -32
- package/docs/guides/connect-discord.md +178 -0
- package/docs/guides/connect-slack.md +126 -0
- package/docs/guides/connect-telegram.md +61 -1
- package/docs/guides/connect-whatsapp-evolution.md +121 -0
- package/docs/guides/connect-whatsapp-uazapi.md +139 -0
- package/docs/guides/connect-whatsapp-zapster.md +119 -16
- package/docs/guides/create-agent.md +31 -4
- package/docs/guides/debug-channel.md +159 -0
- package/docs/guides/improve-from-production.md +151 -0
- package/docs/guides/prepare-deploy.md +32 -14
- package/docs/guides/replay-production-traces.md +72 -0
- package/docs/guides/run-evals.md +95 -25
- package/docs/guides/security-rules.md +9 -5
- package/docs/guides/send-feedback.md +135 -0
- package/docs/guides/use-jev.md +67 -0
- package/docs/guides/use-provider.md +70 -3
- package/docs/llms-full.txt +295 -25
- package/docs/llms.txt +54 -7
- package/package.json +3 -7
- package/src/cli/args.ts +23 -2
- package/src/cli/cloud-client.ts +121 -9
- package/src/cli/commands/channels.ts +1185 -50
- package/src/cli/commands/feedback.ts +438 -0
- package/src/cli/commands/provider.ts +47 -0
- package/src/cli/commands/transcribe.ts +171 -0
- package/src/cli/deploy-chat-ui.ts +232 -18
- package/src/cli/deploy-readiness.ts +227 -14
- package/src/cli/help.ts +68 -8
- package/src/cli/index.ts +740 -35
- package/src/cli/new-command.ts +41 -0
- package/src/cloud/client.ts +4 -3
- package/src/cloud/contracts.ts +1 -1
- package/src/create-project.ts +18 -35
- package/src/index.ts +565 -11
- package/src/providers/codex-auth.ts +111 -0
- package/src/providers/pi.ts +88 -19
- package/src/providers/test.ts +36 -0
- package/src/providers/types.ts +8 -0
- package/src/runtime/channel-test-harness.ts +21 -1
- package/src/runtime/channels/discord.ts +896 -0
- package/src/runtime/channels/generic-webhook.ts +974 -0
- package/src/runtime/channels/slack.ts +646 -0
- package/src/runtime/channels/telegram.ts +466 -23
- package/src/runtime/channels/whatsapp-evolution.ts +1357 -0
- package/src/runtime/channels/whatsapp-meta.ts +9 -0
- package/src/runtime/channels/whatsapp-uazapi.ts +1323 -0
- package/src/runtime/channels/whatsapp-zapster.ts +674 -40
- package/src/runtime/channels.ts +89 -4
- package/src/runtime/chat.ts +70 -44
- package/src/runtime/config.ts +489 -20
- package/src/runtime/core/manifest.ts +75 -5
- package/src/runtime/core/targets.ts +5 -5
- package/src/runtime/deploy-readiness.ts +34 -4
- package/src/runtime/dev-server.ts +639 -39
- package/src/runtime/env.ts +8 -3
- package/src/runtime/evals.ts +445 -74
- package/src/runtime/improve.ts +868 -0
- package/src/runtime/inspect.ts +173 -4
- package/src/runtime/integrations/composio.ts +425 -0
- package/src/runtime/knowledge/retrieve.ts +25 -5
- package/src/runtime/knowledge/schema.ts +45 -1
- package/src/runtime/prompt-context.ts +141 -0
- package/src/runtime/runtime-contract.ts +71 -7
- package/src/runtime/skills.ts +95 -0
- package/src/runtime/targets/cloudflare/build.ts +1010 -208
- package/src/runtime/targets/container/server.ts +1 -1
- package/src/runtime/targets/vps/deploy.ts +26 -9
- package/src/runtime/tool-runner.ts +9 -1
- package/src/runtime/tools.ts +26 -2
- package/src/runtime/transcription.ts +483 -0
- package/src/storage/sqlite.ts +7 -2
- package/src/templates/blank.ts +37 -9
- package/src/templates/dentista.ts +40 -14
- package/src/templates/skills/agentkit-build-agent/SKILL.md +34 -5
- package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md +2 -1
- package/src/templates/skills/agentkit-capsule/SKILL.md +32 -3
- package/src/templates/skills/agentkit-capsule/references/docs-router.md +2 -2
- package/src/templates/skills/agentkit-channels/SKILL.md +71 -6
- package/src/templates/skills/agentkit-channels/references/channel-buffering.md +9 -2
- package/src/templates/skills/agentkit-channels/references/channel-debugging.md +34 -5
- package/src/templates/skills/agentkit-channels/references/discord.md +93 -0
- package/src/templates/skills/agentkit-channels/references/slack.md +56 -0
- package/src/templates/skills/agentkit-channels/references/telegram.md +39 -4
- package/src/templates/skills/agentkit-channels/references/whatsapp-evolution.md +57 -0
- package/src/templates/skills/agentkit-channels/references/whatsapp-uazapi.md +54 -0
- package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +42 -8
- package/src/templates/skills/agentkit-database/SKILL.md +11 -0
- package/src/templates/skills/agentkit-deploy/SKILL.md +9 -1
- package/src/templates/skills/agentkit-evals/SKILL.md +77 -13
- package/src/templates/skills/agentkit-evals/templates/multi-turn.eval.md +13 -6
- package/src/templates/skills/agentkit-evals/templates/no-leak.eval.md +8 -4
- package/src/templates/skills/agentkit-evals/templates/smoke.eval.md +8 -4
- package/src/templates/skills/agentkit-evals/templates/tool-call.eval.md +16 -7
- package/src/templates/skills/agentkit-improve/SKILL.md +96 -0
- package/src/templates/skills/agentkit-improve/references/replay-side-effects.md +18 -0
- package/src/templates/skills/agentkit-improve/references/trace-packets.md +22 -0
- package/src/templates/skills/agentkit-improve/templates/regression.eval.md +18 -0
- package/src/templates/skills/agentkit-integrations/SKILL.md +98 -0
- package/src/templates/skills/agentkit-knowledge/SKILL.md +4 -1
- package/src/templates/skills/agentkit-prompts/SKILL.md +3 -1
- package/src/templates/skills/agentkit-provider/SKILL.md +29 -4
- package/src/templates/skills/agentkit-security/SKILL.md +5 -2
- package/src/templates/skills/agentkit-tools/SKILL.md +8 -1
- package/src/templates/skills/agentkit-tools/examples/eval-safe-external-action.tool.md +8 -8
- package/src/templates/skills/agentkit-tools/examples/jev-service-fit.tool.md +110 -0
- package/src/templates/skills/agentkit-troubleshooting/SKILL.md +25 -1
- package/src/templates/support.ts +42 -12
- package/docs/guides/agentkit-skills-architecture.md +0 -471
- package/docs/guides/channels-implementation-map.md +0 -243
- package/docs/guides/channels-production-handoff.md +0 -101
- package/docs/portable-deploy-release-checklist.md +0 -41
package/src/index.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
export type AgentRuntime = "local" | "edge";
|
|
2
|
-
export type AgentProviderName = "test" | "openai" | "anthropic" | "openrouter" | "custom";
|
|
2
|
+
export type AgentProviderName = "test" | "openai" | "openai-codex" | "anthropic" | "openrouter" | "opencode" | "opencode-go" | "custom";
|
|
3
3
|
export type AccessMode = "private" | "token" | "public";
|
|
4
4
|
export type ToolVisibility = "user" | "internal";
|
|
5
|
-
export type ChannelType = "website" | "telegram" | "whatsapp";
|
|
6
|
-
export type ChannelProvider = "agentkit" | "telegram" | "zapster" | "meta";
|
|
7
|
-
export type WhatsappChannelProvider = "zapster" | "meta";
|
|
5
|
+
export type ChannelType = "website" | "telegram" | "whatsapp" | "discord" | "slack" | "webhook";
|
|
6
|
+
export type ChannelProvider = "agentkit" | "telegram" | "zapster" | "meta" | "uazapi" | "evolution" | "discord" | "slack" | "generic";
|
|
7
|
+
export type WhatsappChannelProvider = "zapster" | "meta" | "uazapi" | "evolution";
|
|
8
|
+
export type DiscordChannelMode = "interactions" | "bot";
|
|
8
9
|
export type TelegramAllowedUpdate = "message";
|
|
10
|
+
export type ChannelAudioMode = "off" | "reject" | "transcribe";
|
|
11
|
+
export type TranscriptionProviderName = "test" | "openai" | "groq";
|
|
12
|
+
export type GenericWebhookDirection = "inbound" | "outbound";
|
|
9
13
|
|
|
10
14
|
export type AgentProvider = {
|
|
11
15
|
name: AgentProviderName;
|
|
@@ -39,6 +43,76 @@ export type ChannelBufferConfig =
|
|
|
39
43
|
maxChars: number;
|
|
40
44
|
};
|
|
41
45
|
|
|
46
|
+
export type ChannelAudioInput = {
|
|
47
|
+
mode?: ChannelAudioMode;
|
|
48
|
+
fallbackMessage?: string;
|
|
49
|
+
maxDurationSeconds?: number;
|
|
50
|
+
maxBytes?: number;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type ChannelAudioConfig =
|
|
54
|
+
| {
|
|
55
|
+
mode: "off";
|
|
56
|
+
}
|
|
57
|
+
| {
|
|
58
|
+
mode: "reject";
|
|
59
|
+
fallbackMessage: string;
|
|
60
|
+
maxDurationSeconds?: number;
|
|
61
|
+
maxBytes?: number;
|
|
62
|
+
}
|
|
63
|
+
| {
|
|
64
|
+
mode: "transcribe";
|
|
65
|
+
fallbackMessage: string;
|
|
66
|
+
maxDurationSeconds?: number;
|
|
67
|
+
maxBytes?: number;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type ChannelReplyRouteInput = {
|
|
71
|
+
channel: string;
|
|
72
|
+
recipientFrom?: string;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export type ChannelReplyRouteConfig = {
|
|
76
|
+
channel: string;
|
|
77
|
+
recipientFrom?: string;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export type GenericWebhookOutputAuthInput =
|
|
81
|
+
| {
|
|
82
|
+
type: "none";
|
|
83
|
+
}
|
|
84
|
+
| {
|
|
85
|
+
type: "bearer";
|
|
86
|
+
tokenSecret: string;
|
|
87
|
+
}
|
|
88
|
+
| {
|
|
89
|
+
type: "header";
|
|
90
|
+
headerName: string;
|
|
91
|
+
valueSecret: string;
|
|
92
|
+
}
|
|
93
|
+
| {
|
|
94
|
+
type: "hmac";
|
|
95
|
+
secret: string;
|
|
96
|
+
headerName?: string;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export type GenericWebhookOutputAuthConfig = GenericWebhookOutputAuthInput;
|
|
100
|
+
|
|
101
|
+
export type AgentTranscriptionLimits = {
|
|
102
|
+
maxDurationSeconds?: number;
|
|
103
|
+
maxBytes?: number;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export type AgentTranscriptionConfig = {
|
|
107
|
+
provider: TranscriptionProviderName;
|
|
108
|
+
model: string;
|
|
109
|
+
secret?: string;
|
|
110
|
+
language?: string;
|
|
111
|
+
prompt?: string;
|
|
112
|
+
limits?: AgentTranscriptionLimits;
|
|
113
|
+
rawAudioTtlSeconds?: number;
|
|
114
|
+
};
|
|
115
|
+
|
|
42
116
|
export type WebsiteChannelAccess = {
|
|
43
117
|
mode: "token";
|
|
44
118
|
};
|
|
@@ -49,6 +123,8 @@ export type WebsiteChannelInput = {
|
|
|
49
123
|
secrets?: string[];
|
|
50
124
|
limits?: ChannelLimits;
|
|
51
125
|
buffer?: ChannelBufferInput;
|
|
126
|
+
audio?: ChannelAudioInput;
|
|
127
|
+
replyTo?: ChannelReplyRouteInput;
|
|
52
128
|
};
|
|
53
129
|
|
|
54
130
|
export type WebsiteChannelConfig = {
|
|
@@ -59,6 +135,8 @@ export type WebsiteChannelConfig = {
|
|
|
59
135
|
secrets: string[];
|
|
60
136
|
limits?: ChannelLimits;
|
|
61
137
|
buffer?: ChannelBufferConfig;
|
|
138
|
+
audio?: ChannelAudioConfig;
|
|
139
|
+
replyTo?: ChannelReplyRouteConfig;
|
|
62
140
|
};
|
|
63
141
|
|
|
64
142
|
export type TelegramChannelInput = {
|
|
@@ -67,6 +145,8 @@ export type TelegramChannelInput = {
|
|
|
67
145
|
allowedUpdates?: TelegramAllowedUpdate[];
|
|
68
146
|
limits?: ChannelLimits;
|
|
69
147
|
buffer?: ChannelBufferInput;
|
|
148
|
+
audio?: ChannelAudioInput;
|
|
149
|
+
replyTo?: ChannelReplyRouteInput;
|
|
70
150
|
};
|
|
71
151
|
|
|
72
152
|
export type TelegramChannelConfig = {
|
|
@@ -77,6 +157,8 @@ export type TelegramChannelConfig = {
|
|
|
77
157
|
allowedUpdates: TelegramAllowedUpdate[];
|
|
78
158
|
limits?: ChannelLimits;
|
|
79
159
|
buffer?: ChannelBufferConfig;
|
|
160
|
+
audio?: ChannelAudioConfig;
|
|
161
|
+
replyTo?: ChannelReplyRouteConfig;
|
|
80
162
|
};
|
|
81
163
|
|
|
82
164
|
export type WhatsappChannelInput = {
|
|
@@ -85,6 +167,8 @@ export type WhatsappChannelInput = {
|
|
|
85
167
|
secrets?: string[];
|
|
86
168
|
limits?: ChannelLimits;
|
|
87
169
|
buffer?: ChannelBufferInput;
|
|
170
|
+
audio?: ChannelAudioInput;
|
|
171
|
+
replyTo?: ChannelReplyRouteInput;
|
|
88
172
|
};
|
|
89
173
|
|
|
90
174
|
export type WhatsappChannelConfig = {
|
|
@@ -94,9 +178,128 @@ export type WhatsappChannelConfig = {
|
|
|
94
178
|
secrets: string[];
|
|
95
179
|
limits?: ChannelLimits;
|
|
96
180
|
buffer?: ChannelBufferConfig;
|
|
181
|
+
audio?: ChannelAudioConfig;
|
|
182
|
+
replyTo?: ChannelReplyRouteConfig;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export type DiscordChannelInput = {
|
|
186
|
+
name: string;
|
|
187
|
+
mode?: DiscordChannelMode;
|
|
188
|
+
secrets?: string[];
|
|
189
|
+
limits?: ChannelLimits;
|
|
190
|
+
buffer?: ChannelBufferInput;
|
|
191
|
+
replyTo?: ChannelReplyRouteInput;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export type DiscordChannelConfig = {
|
|
195
|
+
type: "discord";
|
|
196
|
+
provider: "discord";
|
|
197
|
+
name: string;
|
|
198
|
+
mode: DiscordChannelMode;
|
|
199
|
+
secrets: string[];
|
|
200
|
+
limits?: ChannelLimits;
|
|
201
|
+
buffer?: ChannelBufferConfig;
|
|
202
|
+
replyTo?: ChannelReplyRouteConfig;
|
|
203
|
+
audio?: never;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
export type SlackChannelInput = {
|
|
207
|
+
name: string;
|
|
208
|
+
secrets?: string[];
|
|
209
|
+
limits?: ChannelLimits;
|
|
210
|
+
buffer?: ChannelBufferInput;
|
|
211
|
+
replyTo?: ChannelReplyRouteInput;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
export type SlackChannelConfig = {
|
|
215
|
+
type: "slack";
|
|
216
|
+
provider: "slack";
|
|
217
|
+
name: string;
|
|
218
|
+
secrets: string[];
|
|
219
|
+
limits?: ChannelLimits;
|
|
220
|
+
buffer?: ChannelBufferConfig;
|
|
221
|
+
replyTo?: ChannelReplyRouteConfig;
|
|
222
|
+
audio?: never;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export type GenericWebhookChannelInput = {
|
|
226
|
+
name: string;
|
|
227
|
+
secrets?: string[];
|
|
228
|
+
limits?: ChannelLimits;
|
|
229
|
+
buffer?: ChannelBufferInput;
|
|
230
|
+
replyTo?: ChannelReplyRouteInput;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export type GenericWebhookChannelConfig = {
|
|
234
|
+
type: "webhook";
|
|
235
|
+
provider: "generic";
|
|
236
|
+
direction: "inbound";
|
|
237
|
+
name: string;
|
|
238
|
+
secrets: string[];
|
|
239
|
+
limits?: ChannelLimits;
|
|
240
|
+
buffer?: ChannelBufferConfig;
|
|
241
|
+
replyTo?: ChannelReplyRouteConfig;
|
|
242
|
+
urlSecret?: never;
|
|
243
|
+
auth?: never;
|
|
244
|
+
audio?: never;
|
|
97
245
|
};
|
|
98
246
|
|
|
99
|
-
export type
|
|
247
|
+
export type GenericWebhookOutputChannelInput = {
|
|
248
|
+
name: string;
|
|
249
|
+
urlSecret: string;
|
|
250
|
+
auth?: GenericWebhookOutputAuthInput;
|
|
251
|
+
secrets?: string[];
|
|
252
|
+
limits?: ChannelLimits;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export type GenericWebhookOutputChannelConfig = {
|
|
256
|
+
type: "webhook";
|
|
257
|
+
provider: "generic";
|
|
258
|
+
direction: "outbound";
|
|
259
|
+
name: string;
|
|
260
|
+
urlSecret: string;
|
|
261
|
+
auth: GenericWebhookOutputAuthConfig;
|
|
262
|
+
secrets: string[];
|
|
263
|
+
limits?: ChannelLimits;
|
|
264
|
+
buffer?: never;
|
|
265
|
+
replyTo?: never;
|
|
266
|
+
audio?: never;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export type AgentChannel =
|
|
270
|
+
| WebsiteChannelConfig
|
|
271
|
+
| TelegramChannelConfig
|
|
272
|
+
| WhatsappChannelConfig
|
|
273
|
+
| DiscordChannelConfig
|
|
274
|
+
| SlackChannelConfig
|
|
275
|
+
| GenericWebhookChannelConfig
|
|
276
|
+
| GenericWebhookOutputChannelConfig;
|
|
277
|
+
|
|
278
|
+
export type IntegrationTagsConfig = {
|
|
279
|
+
enable?: string[];
|
|
280
|
+
disable?: string[];
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
export type ComposioManagedIntegrationInput = {
|
|
284
|
+
name?: string;
|
|
285
|
+
toolkits: string[];
|
|
286
|
+
tools?: Record<string, string[]>;
|
|
287
|
+
tags?: IntegrationTagsConfig;
|
|
288
|
+
confirmExternalWrites?: boolean;
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
export type ComposioManagedIntegration = {
|
|
292
|
+
type: "composio";
|
|
293
|
+
provider: "composio";
|
|
294
|
+
mode: "managed";
|
|
295
|
+
name: string;
|
|
296
|
+
toolkits: string[];
|
|
297
|
+
tools?: Record<string, string[]>;
|
|
298
|
+
tags?: IntegrationTagsConfig;
|
|
299
|
+
confirmExternalWrites?: boolean;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
export type AgentIntegration = ComposioManagedIntegration;
|
|
100
303
|
|
|
101
304
|
export type AgentDatabaseConfig =
|
|
102
305
|
| {
|
|
@@ -210,6 +413,7 @@ export type ToolRenderResult = {
|
|
|
210
413
|
export type ToolRenderContext<Input = unknown> = {
|
|
211
414
|
input: Input;
|
|
212
415
|
runtime: ToolRuntimeContext;
|
|
416
|
+
clock: ToolClockContext;
|
|
213
417
|
};
|
|
214
418
|
|
|
215
419
|
export type ToolRuntimeContext = {
|
|
@@ -219,10 +423,20 @@ export type ToolRuntimeContext = {
|
|
|
219
423
|
database: "sqlite" | "turso" | "none";
|
|
220
424
|
};
|
|
221
425
|
|
|
426
|
+
export type ToolClockContext = {
|
|
427
|
+
now: Date;
|
|
428
|
+
isoTimestamp: string;
|
|
429
|
+
timeZone: string;
|
|
430
|
+
localDate: string;
|
|
431
|
+
localWeekday: string;
|
|
432
|
+
localDateTime: string;
|
|
433
|
+
};
|
|
434
|
+
|
|
222
435
|
export type ToolContext = {
|
|
223
436
|
secrets: Record<string, string>;
|
|
224
437
|
signal: AbortSignal;
|
|
225
438
|
runtime: ToolRuntimeContext;
|
|
439
|
+
clock: ToolClockContext;
|
|
226
440
|
database: DatabaseRunner;
|
|
227
441
|
db: DatabaseRunner;
|
|
228
442
|
storage: {
|
|
@@ -254,10 +468,13 @@ export type AgentConfig = {
|
|
|
254
468
|
name: string;
|
|
255
469
|
runtime: AgentRuntime;
|
|
256
470
|
provider: AgentProvider;
|
|
471
|
+
timeZone?: string;
|
|
257
472
|
instructions: string;
|
|
258
473
|
secrets: string[];
|
|
259
474
|
tools?: AgentTool[];
|
|
475
|
+
integrations?: AgentIntegration[];
|
|
260
476
|
channels?: AgentChannel[];
|
|
477
|
+
transcription?: AgentTranscriptionConfig;
|
|
261
478
|
knowledge?: AgentKnowledgeConfig;
|
|
262
479
|
access: {
|
|
263
480
|
mode: AccessMode;
|
|
@@ -278,6 +495,25 @@ export function defineTool<Input = unknown, Output = unknown>(tool: AgentTool<In
|
|
|
278
495
|
return tool;
|
|
279
496
|
}
|
|
280
497
|
|
|
498
|
+
export function composioManaged(input: ComposioManagedIntegrationInput): ComposioManagedIntegration {
|
|
499
|
+
const name = normalizeIntegrationName(input.name ?? "composio", "composio integration name");
|
|
500
|
+
const toolkits = normalizeToolkitList(input.toolkits, "composioManaged.toolkits");
|
|
501
|
+
const tools = input.tools ? normalizeComposioToolMap(input.tools, toolkits) : undefined;
|
|
502
|
+
const tags = input.tags ? normalizeIntegrationTags(input.tags) : undefined;
|
|
503
|
+
const confirmExternalWrites = input.confirmExternalWrites;
|
|
504
|
+
|
|
505
|
+
return {
|
|
506
|
+
type: "composio",
|
|
507
|
+
provider: "composio",
|
|
508
|
+
mode: "managed",
|
|
509
|
+
name,
|
|
510
|
+
toolkits,
|
|
511
|
+
...(tools ? { tools } : {}),
|
|
512
|
+
...(tags ? { tags } : {}),
|
|
513
|
+
...(confirmExternalWrites === undefined ? {} : { confirmExternalWrites }),
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
281
517
|
export function websiteChannel(input: WebsiteChannelInput): WebsiteChannelConfig {
|
|
282
518
|
return {
|
|
283
519
|
type: "website",
|
|
@@ -287,6 +523,8 @@ export function websiteChannel(input: WebsiteChannelInput): WebsiteChannelConfig
|
|
|
287
523
|
secrets: normalizeChannelSecrets(input.secrets ?? ["AGENTKIT_WEBSITE_CHANNEL_TOKEN"], "website channel"),
|
|
288
524
|
...(input.limits ? { limits: input.limits } : {}),
|
|
289
525
|
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "website channel") } : {}),
|
|
526
|
+
...(input.audio ? { audio: normalizeChannelAudio(input.audio, "website channel") } : {}),
|
|
527
|
+
...(input.replyTo ? { replyTo: normalizeChannelReplyRoute(input.replyTo, "website channel") } : {}),
|
|
290
528
|
};
|
|
291
529
|
}
|
|
292
530
|
|
|
@@ -302,6 +540,8 @@ export function telegramChannel(input: TelegramChannelInput): TelegramChannelCon
|
|
|
302
540
|
allowedUpdates: input.allowedUpdates ?? ["message"],
|
|
303
541
|
...(input.limits ? { limits: input.limits } : {}),
|
|
304
542
|
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "telegram channel") } : {}),
|
|
543
|
+
...(input.audio ? { audio: normalizeChannelAudio(input.audio, "telegram channel") } : {}),
|
|
544
|
+
...(input.replyTo ? { replyTo: normalizeChannelReplyRoute(input.replyTo, "telegram channel") } : {}),
|
|
305
545
|
};
|
|
306
546
|
}
|
|
307
547
|
|
|
@@ -316,12 +556,86 @@ export function whatsappChannel(input: WhatsappChannelInput): WhatsappChannelCon
|
|
|
316
556
|
),
|
|
317
557
|
...(input.limits ? { limits: input.limits } : {}),
|
|
318
558
|
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, `${input.provider} whatsapp channel`) } : {}),
|
|
559
|
+
...(input.audio ? { audio: normalizeChannelAudio(input.audio, `${input.provider} whatsapp channel`) } : {}),
|
|
560
|
+
...(input.replyTo ? { replyTo: normalizeChannelReplyRoute(input.replyTo, `${input.provider} whatsapp channel`) } : {}),
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
export function discordChannel(input: DiscordChannelInput): DiscordChannelConfig {
|
|
565
|
+
const mode = input.mode ?? "interactions";
|
|
566
|
+
|
|
567
|
+
return {
|
|
568
|
+
type: "discord",
|
|
569
|
+
provider: "discord",
|
|
570
|
+
name: input.name,
|
|
571
|
+
mode,
|
|
572
|
+
secrets: normalizeChannelSecrets(input.secrets ?? defaultDiscordChannelSecrets(mode), "discord channel"),
|
|
573
|
+
...(input.limits ? { limits: input.limits } : {}),
|
|
574
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "discord channel") } : {}),
|
|
575
|
+
...(input.replyTo ? { replyTo: normalizeChannelReplyRoute(input.replyTo, "discord channel") } : {}),
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
export function slackChannel(input: SlackChannelInput): SlackChannelConfig {
|
|
580
|
+
return {
|
|
581
|
+
type: "slack",
|
|
582
|
+
provider: "slack",
|
|
583
|
+
name: input.name,
|
|
584
|
+
secrets: normalizeChannelSecrets(input.secrets ?? ["SLACK_BOT_TOKEN", "SLACK_SIGNING_SECRET"], "slack channel"),
|
|
585
|
+
...(input.limits ? { limits: input.limits } : {}),
|
|
586
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "slack channel") } : {}),
|
|
587
|
+
...(input.replyTo ? { replyTo: normalizeChannelReplyRoute(input.replyTo, "slack channel") } : {}),
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
export function webhookChannel(input: GenericWebhookChannelInput): GenericWebhookChannelConfig {
|
|
592
|
+
return {
|
|
593
|
+
type: "webhook",
|
|
594
|
+
provider: "generic",
|
|
595
|
+
direction: "inbound",
|
|
596
|
+
name: input.name,
|
|
597
|
+
secrets: normalizeChannelSecrets(input.secrets ?? ["AGENTKIT_WEBHOOK_SECRET"], "generic webhook channel"),
|
|
598
|
+
...(input.limits ? { limits: input.limits } : {}),
|
|
599
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "generic webhook channel") } : {}),
|
|
600
|
+
...(input.replyTo ? { replyTo: normalizeChannelReplyRoute(input.replyTo, "generic webhook channel") } : {}),
|
|
319
601
|
};
|
|
320
602
|
}
|
|
321
603
|
|
|
604
|
+
export function webhookOutputChannel(input: GenericWebhookOutputChannelInput): GenericWebhookOutputChannelConfig {
|
|
605
|
+
const auth = normalizeGenericWebhookOutputAuth(input.auth ?? { type: "none" }, "generic webhook output channel");
|
|
606
|
+
const requiredSecrets = [
|
|
607
|
+
input.urlSecret,
|
|
608
|
+
...genericWebhookOutputAuthSecrets(auth),
|
|
609
|
+
...(input.secrets ?? []),
|
|
610
|
+
];
|
|
611
|
+
|
|
612
|
+
return {
|
|
613
|
+
type: "webhook",
|
|
614
|
+
provider: "generic",
|
|
615
|
+
direction: "outbound",
|
|
616
|
+
name: input.name,
|
|
617
|
+
urlSecret: normalizeSecretName(input.urlSecret, "generic webhook output channel urlSecret"),
|
|
618
|
+
auth,
|
|
619
|
+
secrets: normalizeChannelSecrets(requiredSecrets, "generic webhook output channel"),
|
|
620
|
+
...(input.limits ? { limits: input.limits } : {}),
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function defaultDiscordChannelSecrets(mode: DiscordChannelMode): string[] {
|
|
625
|
+
return mode === "bot" ? ["DISCORD_BOT_TOKEN"] : ["DISCORD_PUBLIC_KEY"];
|
|
626
|
+
}
|
|
627
|
+
|
|
322
628
|
function defaultWhatsappChannelSecrets(provider: WhatsappChannelProvider): string[] {
|
|
323
629
|
if (provider === "zapster") {
|
|
324
|
-
return ["ZAPSTER_API_KEY", "
|
|
630
|
+
return ["ZAPSTER_API_KEY", "ZAPSTER_INSTANCE_ID", "ZAPSTER_WEBHOOK_ID", "ZAPSTER_WEBHOOK_TOKEN"];
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (provider === "uazapi") {
|
|
634
|
+
return ["UAZAPI_BASE_URL", "UAZAPI_TOKEN", "UAZAPI_WEBHOOK_TOKEN"];
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (provider === "evolution") {
|
|
638
|
+
return ["EVOLUTION_API_BASE_URL", "EVOLUTION_API_KEY", "EVOLUTION_INSTANCE_NAME", "EVOLUTION_WEBHOOK_TOKEN"];
|
|
325
639
|
}
|
|
326
640
|
|
|
327
641
|
return ["META_WHATSAPP_ACCESS_TOKEN", "META_WHATSAPP_APP_SECRET", "META_WHATSAPP_VERIFY_TOKEN"];
|
|
@@ -331,14 +645,125 @@ function normalizeChannelSecrets(secrets: string[], context: string): string[] {
|
|
|
331
645
|
const uniqueSecrets = new Set<string>();
|
|
332
646
|
|
|
333
647
|
for (const secret of secrets) {
|
|
334
|
-
|
|
335
|
-
|
|
648
|
+
uniqueSecrets.add(normalizeSecretName(secret, `${context} secrets`));
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return Array.from(uniqueSecrets).sort();
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function normalizeSecretName(secret: string, context: string): string {
|
|
655
|
+
if (!/^[A-Z_][A-Z0-9_]*$/.test(secret)) {
|
|
656
|
+
if (context.endsWith("secrets")) {
|
|
657
|
+
throw new Error(`${context} must be environment variable names, not secret values.`);
|
|
336
658
|
}
|
|
337
659
|
|
|
338
|
-
|
|
660
|
+
throw new Error(`${context} must be an environment variable name, not a secret value.`);
|
|
339
661
|
}
|
|
340
662
|
|
|
341
|
-
return
|
|
663
|
+
return secret;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function normalizeIntegrationName(value: string, context: string): string {
|
|
667
|
+
const name = value.trim();
|
|
668
|
+
|
|
669
|
+
if (!/^[a-z][a-z0-9-]*$/.test(name)) {
|
|
670
|
+
throw new Error(`${context} must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return name;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function normalizeToolkitList(values: string[], context: string): string[] {
|
|
677
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
678
|
+
throw new Error(`${context} must include at least one toolkit slug.`);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const toolkits = new Set<string>();
|
|
682
|
+
|
|
683
|
+
for (const value of values) {
|
|
684
|
+
if (typeof value !== "string") {
|
|
685
|
+
throw new Error(`${context} entries must be toolkit slug strings.`);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const toolkit = value.trim().toLowerCase();
|
|
689
|
+
|
|
690
|
+
if (!/^[a-z][a-z0-9_-]*$/.test(toolkit)) {
|
|
691
|
+
throw new Error(`${context} entries must start with a letter and contain only letters, numbers, underscores, and hyphens.`);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
toolkits.add(toolkit);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return Array.from(toolkits).sort();
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
function normalizeComposioToolMap(values: Record<string, string[]>, toolkits: string[]): Record<string, string[]> | undefined {
|
|
701
|
+
const toolkitSet = new Set(toolkits);
|
|
702
|
+
const normalized: Record<string, string[]> = {};
|
|
703
|
+
|
|
704
|
+
for (const [rawToolkit, rawTools] of Object.entries(values)) {
|
|
705
|
+
const toolkit = rawToolkit.trim().toLowerCase();
|
|
706
|
+
|
|
707
|
+
if (!toolkitSet.has(toolkit)) {
|
|
708
|
+
throw new Error(`composioManaged.tools.${rawToolkit} must reference a toolkit listed in composioManaged.toolkits.`);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if (!Array.isArray(rawTools) || rawTools.length === 0) {
|
|
712
|
+
throw new Error(`composioManaged.tools.${rawToolkit} must include at least one Composio action slug.`);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const tools = new Set<string>();
|
|
716
|
+
|
|
717
|
+
for (const rawTool of rawTools) {
|
|
718
|
+
if (typeof rawTool !== "string") {
|
|
719
|
+
throw new Error(`composioManaged.tools.${rawToolkit} entries must be Composio action slug strings.`);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
const tool = rawTool.trim().toUpperCase();
|
|
723
|
+
|
|
724
|
+
if (!/^[A-Z][A-Z0-9_]*$/.test(tool)) {
|
|
725
|
+
throw new Error(`composioManaged.tools.${rawToolkit} entries must be uppercase Composio action slugs.`);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
tools.add(tool);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
normalized[toolkit] = Array.from(tools).sort();
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
return Object.keys(normalized).length > 0 ? normalized : undefined;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function normalizeIntegrationTags(tags: IntegrationTagsConfig): IntegrationTagsConfig {
|
|
738
|
+
const normalized: IntegrationTagsConfig = {};
|
|
739
|
+
|
|
740
|
+
if (tags.enable !== undefined) {
|
|
741
|
+
normalized.enable = normalizeTagList(tags.enable, "composioManaged.tags.enable");
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
if (tags.disable !== undefined) {
|
|
745
|
+
normalized.disable = normalizeTagList(tags.disable, "composioManaged.tags.disable");
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
return normalized;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
function normalizeTagList(values: string[], context: string): string[] {
|
|
752
|
+
if (!Array.isArray(values)) {
|
|
753
|
+
throw new Error(`${context} must be an array of tag strings.`);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return Array.from(
|
|
757
|
+
new Set(
|
|
758
|
+
values.map((value) => {
|
|
759
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
760
|
+
throw new Error(`${context} entries must be non-empty strings.`);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
return value.trim();
|
|
764
|
+
}),
|
|
765
|
+
),
|
|
766
|
+
).sort();
|
|
342
767
|
}
|
|
343
768
|
|
|
344
769
|
function normalizeChannelBuffer(input: ChannelBufferInput, context: string): ChannelBufferConfig {
|
|
@@ -370,6 +795,114 @@ function normalizeChannelBuffer(input: ChannelBufferInput, context: string): Cha
|
|
|
370
795
|
return buffer;
|
|
371
796
|
}
|
|
372
797
|
|
|
798
|
+
function normalizeChannelAudio(input: ChannelAudioInput, context: string): ChannelAudioConfig {
|
|
799
|
+
const mode = input.mode ?? "transcribe";
|
|
800
|
+
|
|
801
|
+
if (mode !== "off" && mode !== "reject" && mode !== "transcribe") {
|
|
802
|
+
throw new Error(`${context} audio.mode must be "off", "reject", or "transcribe".`);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
if (mode === "off") {
|
|
806
|
+
return { mode: "off" };
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
if (input.maxDurationSeconds !== undefined) {
|
|
810
|
+
validatePositiveInteger(input.maxDurationSeconds, `${context} audio.maxDurationSeconds`);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (input.maxBytes !== undefined) {
|
|
814
|
+
validatePositiveInteger(input.maxBytes, `${context} audio.maxBytes`);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return {
|
|
818
|
+
mode,
|
|
819
|
+
fallbackMessage: input.fallbackMessage ?? "I received an audio message, but I could not transcribe it. Please send the message as text.",
|
|
820
|
+
...(input.maxDurationSeconds !== undefined ? { maxDurationSeconds: input.maxDurationSeconds } : {}),
|
|
821
|
+
...(input.maxBytes !== undefined ? { maxBytes: input.maxBytes } : {}),
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
function normalizeChannelReplyRoute(input: ChannelReplyRouteInput, context: string): ChannelReplyRouteConfig {
|
|
826
|
+
const channel = input.channel.trim();
|
|
827
|
+
|
|
828
|
+
if (!/^[a-z][a-z0-9-]*$/.test(channel)) {
|
|
829
|
+
throw new Error(`${context} replyTo.channel must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
return {
|
|
833
|
+
channel,
|
|
834
|
+
...(input.recipientFrom ? { recipientFrom: normalizeJsonPath(input.recipientFrom, `${context} replyTo.recipientFrom`) } : {}),
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function normalizeJsonPath(value: string, context: string): string {
|
|
839
|
+
const path = value.trim().replace(/^payload\./, "");
|
|
840
|
+
|
|
841
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(path)) {
|
|
842
|
+
throw new Error(`${context} must be a dotted JSON field path such as "phone" or "customer.phone".`);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
return path;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
function normalizeGenericWebhookOutputAuth(
|
|
849
|
+
auth: GenericWebhookOutputAuthInput,
|
|
850
|
+
context: string,
|
|
851
|
+
): GenericWebhookOutputAuthConfig {
|
|
852
|
+
if (auth.type === "none") {
|
|
853
|
+
return { type: "none" };
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
if (auth.type === "bearer") {
|
|
857
|
+
return {
|
|
858
|
+
type: "bearer",
|
|
859
|
+
tokenSecret: normalizeSecretName(auth.tokenSecret, `${context} auth.tokenSecret`),
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if (auth.type === "header") {
|
|
864
|
+
if (!/^[A-Za-z][A-Za-z0-9-]*$/.test(auth.headerName)) {
|
|
865
|
+
throw new Error(`${context} auth.headerName must be an HTTP header name.`);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
return {
|
|
869
|
+
type: "header",
|
|
870
|
+
headerName: auth.headerName,
|
|
871
|
+
valueSecret: normalizeSecretName(auth.valueSecret, `${context} auth.valueSecret`),
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if (auth.type === "hmac") {
|
|
876
|
+
if (auth.headerName !== undefined && !/^[A-Za-z][A-Za-z0-9-]*$/.test(auth.headerName)) {
|
|
877
|
+
throw new Error(`${context} auth.headerName must be an HTTP header name.`);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
return {
|
|
881
|
+
type: "hmac",
|
|
882
|
+
secret: normalizeSecretName(auth.secret, `${context} auth.secret`),
|
|
883
|
+
...(auth.headerName ? { headerName: auth.headerName } : {}),
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
throw new Error(`${context} auth.type must be "none", "bearer", "header", or "hmac".`);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
function genericWebhookOutputAuthSecrets(auth: GenericWebhookOutputAuthConfig): string[] {
|
|
891
|
+
if (auth.type === "bearer") {
|
|
892
|
+
return [auth.tokenSecret];
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
if (auth.type === "header") {
|
|
896
|
+
return [auth.valueSecret];
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
if (auth.type === "hmac") {
|
|
900
|
+
return [auth.secret];
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
return [];
|
|
904
|
+
}
|
|
905
|
+
|
|
373
906
|
function validatePositiveInteger(value: number, field: string): void {
|
|
374
907
|
if (!Number.isInteger(value) || value <= 0) {
|
|
375
908
|
throw new Error(`${field} must be a positive integer.`);
|
|
@@ -379,7 +912,18 @@ function validatePositiveInteger(value: number, field: string): void {
|
|
|
379
912
|
export { loadAgentCapsule, findAgentCapsuleRoot } from "./runtime/config";
|
|
380
913
|
export { runAgentMessage, runAgentMessageFromCwd } from "./runtime/chat";
|
|
381
914
|
export { listConversationsFromCwd, getConversationFromCwd } from "./runtime/conversations";
|
|
382
|
-
export { runEvalsFromCwd } from "./runtime/evals";
|
|
915
|
+
export { defineEval, runEvalsFromCwd } from "./runtime/evals";
|
|
916
|
+
export type {
|
|
917
|
+
EvalCase,
|
|
918
|
+
EvalExpect,
|
|
919
|
+
EvalResponseExpectation,
|
|
920
|
+
EvalRunSummary,
|
|
921
|
+
EvalResult,
|
|
922
|
+
EvalToolsContainerExpectation,
|
|
923
|
+
EvalToolsExpectation,
|
|
924
|
+
EvalTurn,
|
|
925
|
+
ToolExpectation,
|
|
926
|
+
} from "./runtime/evals";
|
|
383
927
|
export { getConversationTraceFromCwd } from "./runtime/traces";
|
|
384
928
|
export { runToolFromCwd } from "./runtime/tool-runner";
|
|
385
929
|
export { startAgentDevServer } from "./runtime/dev-server";
|
|
@@ -390,19 +934,29 @@ export { AgentKitError } from "./runtime/errors";
|
|
|
390
934
|
export type {
|
|
391
935
|
ChannelAdapter,
|
|
392
936
|
ChannelAdapterId,
|
|
937
|
+
ChannelAudioAttachment,
|
|
393
938
|
ChannelDeliveryDirection,
|
|
394
939
|
ChannelDeliveryState,
|
|
395
940
|
ChannelEventKind,
|
|
396
941
|
ChannelExternalIdentity,
|
|
942
|
+
ChannelMediaDownloadInput,
|
|
943
|
+
ChannelMediaDownloadResult,
|
|
397
944
|
ChannelMessageContentType,
|
|
398
945
|
ChannelMessageRole,
|
|
946
|
+
ChannelReplyTarget,
|
|
399
947
|
ChannelSendInput,
|
|
400
948
|
ChannelSendResult,
|
|
401
949
|
ChannelStatusInput,
|
|
402
950
|
ChannelStatusResult,
|
|
951
|
+
ChannelWebhookResponse,
|
|
403
952
|
NormalizedChannelEvent,
|
|
404
953
|
NormalizedChannelMessage,
|
|
405
954
|
RawWebhookEvent,
|
|
406
955
|
WebhookVerificationInput,
|
|
407
956
|
WebhookVerificationResult,
|
|
408
957
|
} from "./runtime/channels";
|
|
958
|
+
export type {
|
|
959
|
+
TranscriptionAdapter,
|
|
960
|
+
TranscriptionInput,
|
|
961
|
+
TranscriptionResult,
|
|
962
|
+
} from "./runtime/transcription";
|