@andreprado/agentkit 0.1.0-alpha.15 → 0.1.0-alpha.17
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 +8 -0
- package/docs/guides/add-channel.md +65 -0
- package/docs/guides/add-managed-composio.md +137 -0
- package/docs/guides/channel-security.md +32 -0
- package/docs/guides/channels-production-handoff.md +1 -1
- package/docs/guides/connect-telegram.md +60 -0
- package/docs/guides/connect-whatsapp-zapster.md +65 -0
- package/docs/guides/prepare-deploy.md +3 -1
- package/docs/llms-full.txt +13 -1
- package/docs/llms.txt +7 -0
- package/package.json +1 -1
- package/src/cli/commands/channels.ts +121 -7
- package/src/cli/commands/transcribe.ts +171 -0
- package/src/cli/deploy-readiness.ts +59 -3
- package/src/cli/help.ts +15 -0
- package/src/cli/index.ts +130 -0
- package/src/create-project.ts +4 -32
- package/src/index.ts +231 -0
- package/src/runtime/channel-test-harness.ts +2 -0
- package/src/runtime/channels/telegram.ts +326 -10
- package/src/runtime/channels/whatsapp-zapster.ts +319 -0
- package/src/runtime/channels.ts +47 -1
- package/src/runtime/chat.ts +2 -1
- package/src/runtime/config.ts +214 -4
- package/src/runtime/core/manifest.ts +61 -2
- package/src/runtime/deploy-readiness.ts +31 -1
- package/src/runtime/dev-server.ts +72 -4
- package/src/runtime/inspect.ts +142 -4
- package/src/runtime/integrations/composio.ts +257 -0
- package/src/runtime/skills.ts +95 -0
- package/src/runtime/targets/cloudflare/build.ts +162 -5
- package/src/runtime/tool-runner.ts +2 -1
- package/src/runtime/transcription.ts +483 -0
- package/src/templates/skills/agentkit-capsule/SKILL.md +1 -0
- package/src/templates/skills/agentkit-channels/SKILL.md +36 -1
- package/src/templates/skills/agentkit-channels/references/channel-debugging.md +16 -1
- package/src/templates/skills/agentkit-channels/references/telegram.md +34 -0
- package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +29 -0
- package/src/templates/skills/agentkit-deploy/SKILL.md +1 -1
- package/src/templates/skills/agentkit-integrations/SKILL.md +66 -0
- package/src/templates/skills/agentkit-troubleshooting/SKILL.md +3 -2
package/src/cli/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { runEvalsFromCwd, writeEvalFromConversation } from "../runtime/evals";
|
|
|
22
22
|
import { findAgentKitDocs } from "../runtime/docs";
|
|
23
23
|
import { listCapsuleEnv, setCapsuleEnv, unsetCapsuleEnv } from "../runtime/env";
|
|
24
24
|
import { checkAgentSpec, initializeAgentSpec } from "../runtime/spec";
|
|
25
|
+
import { checkDefaultSkillStatus, syncDefaultSkillFiles } from "../runtime/skills";
|
|
25
26
|
import { initializeSyncScaffold, runCapsuleSync } from "../runtime/sync";
|
|
26
27
|
import { runToolFromCwd } from "../runtime/tool-runner";
|
|
27
28
|
import { startAgentDevServer } from "../runtime/dev-server";
|
|
@@ -67,6 +68,7 @@ import { renderCommandHelp, renderCommandReference, renderHelp } from "./help";
|
|
|
67
68
|
import { runInheritedCommand, waitForShutdown } from "./process";
|
|
68
69
|
import { handleChannelsCommand } from "./commands/channels";
|
|
69
70
|
import { handleKnowledgeCommand } from "./commands/knowledge";
|
|
71
|
+
import { handleTranscribeCommand } from "./commands/transcribe";
|
|
70
72
|
|
|
71
73
|
async function main() {
|
|
72
74
|
const args = parseArgs(process.argv.slice(2));
|
|
@@ -764,6 +766,110 @@ async function main() {
|
|
|
764
766
|
return;
|
|
765
767
|
}
|
|
766
768
|
|
|
769
|
+
if (args.command === "transcribe") {
|
|
770
|
+
await handleTranscribeCommand(args);
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
if (args.command === "skills") {
|
|
775
|
+
const [subcommand] = args.positional;
|
|
776
|
+
const root = await findAgentCapsuleRoot(process.cwd());
|
|
777
|
+
|
|
778
|
+
if (subcommand === "status") {
|
|
779
|
+
const status = await checkDefaultSkillStatus(root);
|
|
780
|
+
printSkillStatus(status);
|
|
781
|
+
if (status.status !== "current") {
|
|
782
|
+
process.exitCode = 1;
|
|
783
|
+
}
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (subcommand === "sync") {
|
|
788
|
+
const result = await syncDefaultSkillFiles(root);
|
|
789
|
+
console.log(`Synced ${result.files.length} AgentKit skill files.`);
|
|
790
|
+
console.log("Status: current");
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
throw new Error("Usage: agentkit skills status | agentkit skills sync");
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
if (args.command === "integrations") {
|
|
798
|
+
const [subcommand, provider] = args.positional;
|
|
799
|
+
|
|
800
|
+
if (provider !== undefined && provider !== "composio") {
|
|
801
|
+
throw new Error("Usage: agentkit integrations status | connect composio [--toolkit <slug>] [--callback-url <url>] [--api <url>]");
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const state = await requireLocalDeployState();
|
|
805
|
+
const apiUrl = await resolveCloudApiUrl(args.flags.api);
|
|
806
|
+
|
|
807
|
+
if (subcommand === "status") {
|
|
808
|
+
const payload = await cloudApiRequest(
|
|
809
|
+
apiUrl,
|
|
810
|
+
`/v1/deploys/${encodeURIComponent(state.deploy_id)}/integrations/composio/status`,
|
|
811
|
+
{ method: "GET" },
|
|
812
|
+
);
|
|
813
|
+
printJson(payload);
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (subcommand === "connect" && provider === "composio") {
|
|
818
|
+
const toolkit = parseOptionalStringFlag(
|
|
819
|
+
args.flags.toolkit,
|
|
820
|
+
"toolkit",
|
|
821
|
+
"agentkit integrations connect composio --toolkit <slug>",
|
|
822
|
+
);
|
|
823
|
+
const callbackUrl = parseOptionalStringFlag(
|
|
824
|
+
args.flags["callback-url"],
|
|
825
|
+
"callback-url",
|
|
826
|
+
"agentkit integrations connect composio --callback-url <url>",
|
|
827
|
+
);
|
|
828
|
+
const payload = (await cloudApiRequest(
|
|
829
|
+
apiUrl,
|
|
830
|
+
`/v1/deploys/${encodeURIComponent(state.deploy_id)}/integrations/composio/connect-link`,
|
|
831
|
+
{
|
|
832
|
+
method: "POST",
|
|
833
|
+
body: JSON.stringify({
|
|
834
|
+
...(toolkit ? { toolkit } : {}),
|
|
835
|
+
...(callbackUrl ? { callback_url: callbackUrl } : {}),
|
|
836
|
+
}),
|
|
837
|
+
},
|
|
838
|
+
)) as {
|
|
839
|
+
connect_link?: {
|
|
840
|
+
toolkit?: string;
|
|
841
|
+
user_id?: string;
|
|
842
|
+
redirect_url?: string;
|
|
843
|
+
expires_at?: string;
|
|
844
|
+
connected_account_id?: string;
|
|
845
|
+
};
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
const link = payload.connect_link;
|
|
849
|
+
|
|
850
|
+
if (!link?.redirect_url) {
|
|
851
|
+
throw new AgentKitError("integration_response_invalid", "AgentKit Cloud returned an invalid Composio connect-link payload.");
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
console.log("Composio connect link");
|
|
855
|
+
console.log(`Toolkit: ${link.toolkit ?? toolkit ?? "unknown"}`);
|
|
856
|
+
console.log(`User: ${link.user_id ?? "unknown"}`);
|
|
857
|
+
console.log(`URL: ${link.redirect_url}`);
|
|
858
|
+
|
|
859
|
+
if (link.expires_at) {
|
|
860
|
+
console.log(`Expires: ${link.expires_at}`);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if (link.connected_account_id) {
|
|
864
|
+
console.log(`Account: ${link.connected_account_id}`);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
throw new Error("Usage: agentkit integrations status | connect composio [--toolkit <slug>] [--callback-url <url>] [--api <url>]");
|
|
871
|
+
}
|
|
872
|
+
|
|
767
873
|
if (args.command === "env") {
|
|
768
874
|
const [subcommand, name, ...valueParts] = args.positional;
|
|
769
875
|
const root = await findAgentCapsuleRoot(process.cwd());
|
|
@@ -1078,6 +1184,30 @@ function printJson(value: unknown): void {
|
|
|
1078
1184
|
console.log(JSON.stringify(value, null, 2));
|
|
1079
1185
|
}
|
|
1080
1186
|
|
|
1187
|
+
function printSkillStatus(status: Awaited<ReturnType<typeof checkDefaultSkillStatus>>): void {
|
|
1188
|
+
console.log("AgentKit skills");
|
|
1189
|
+
console.log(`Status: ${status.status}`);
|
|
1190
|
+
console.log(`Checked: ${status.checked}`);
|
|
1191
|
+
|
|
1192
|
+
if (status.missing.length > 0) {
|
|
1193
|
+
console.log(`Missing: ${status.missing.length}`);
|
|
1194
|
+
for (const file of status.missing.slice(0, 10)) {
|
|
1195
|
+
console.log(` ${file}`);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
if (status.outdated.length > 0) {
|
|
1200
|
+
console.log(`Outdated: ${status.outdated.length}`);
|
|
1201
|
+
for (const file of status.outdated.slice(0, 10)) {
|
|
1202
|
+
console.log(` ${file}`);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
if (status.status !== "current") {
|
|
1207
|
+
console.log("Run: npm run agentkit -- skills sync");
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1081
1211
|
async function printJsonOrWrite(value: unknown, outFlag: string | boolean | undefined, usage: string): Promise<void> {
|
|
1082
1212
|
const outPath = parseOptionalStringFlag(outFlag, "out", usage);
|
|
1083
1213
|
|
package/src/create-project.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
-
import { mkdir, readFile,
|
|
3
|
-
import { basename, dirname, join,
|
|
2
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { loadDefaultSkillFiles } from "./runtime/skills";
|
|
8
|
+
import { getTemplate } from "./templates";
|
|
8
9
|
|
|
9
10
|
const execFileAsync = promisify(execFile);
|
|
10
11
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -129,35 +130,6 @@ async function resolveAgentKitDependency(): Promise<string> {
|
|
|
129
130
|
return packageJson.version;
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
async function loadDefaultSkillFiles(): Promise<TemplateFile[]> {
|
|
133
|
-
const sourceRoot = join(moduleDir, "templates", "skills");
|
|
134
|
-
const sourceFiles = await listFiles(sourceRoot);
|
|
135
|
-
|
|
136
|
-
return Promise.all(
|
|
137
|
-
sourceFiles.map(async (sourcePath) => ({
|
|
138
|
-
path: join("skills", relative(sourceRoot, sourcePath)).replaceAll("\\", "/"),
|
|
139
|
-
contents: await readFile(sourcePath, "utf8"),
|
|
140
|
-
})),
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async function listFiles(directory: string): Promise<string[]> {
|
|
145
|
-
const entries = await readdir(directory, { withFileTypes: true });
|
|
146
|
-
const files = await Promise.all(
|
|
147
|
-
entries.map(async (entry) => {
|
|
148
|
-
const path = join(directory, entry.name);
|
|
149
|
-
|
|
150
|
-
if (entry.isDirectory()) {
|
|
151
|
-
return listFiles(path);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return entry.isFile() ? [path] : [];
|
|
155
|
-
}),
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
return files.flat().sort();
|
|
159
|
-
}
|
|
160
|
-
|
|
161
133
|
async function directoryExists(path: string): Promise<boolean> {
|
|
162
134
|
try {
|
|
163
135
|
const result = await stat(path);
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type ChannelType = "website" | "telegram" | "whatsapp";
|
|
|
6
6
|
export type ChannelProvider = "agentkit" | "telegram" | "zapster" | "meta";
|
|
7
7
|
export type WhatsappChannelProvider = "zapster" | "meta";
|
|
8
8
|
export type TelegramAllowedUpdate = "message";
|
|
9
|
+
export type ChannelAudioMode = "off" | "reject" | "transcribe";
|
|
10
|
+
export type TranscriptionProviderName = "test" | "openai" | "groq";
|
|
9
11
|
|
|
10
12
|
export type AgentProvider = {
|
|
11
13
|
name: AgentProviderName;
|
|
@@ -39,6 +41,45 @@ export type ChannelBufferConfig =
|
|
|
39
41
|
maxChars: number;
|
|
40
42
|
};
|
|
41
43
|
|
|
44
|
+
export type ChannelAudioInput = {
|
|
45
|
+
mode?: ChannelAudioMode;
|
|
46
|
+
fallbackMessage?: string;
|
|
47
|
+
maxDurationSeconds?: number;
|
|
48
|
+
maxBytes?: number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type ChannelAudioConfig =
|
|
52
|
+
| {
|
|
53
|
+
mode: "off";
|
|
54
|
+
}
|
|
55
|
+
| {
|
|
56
|
+
mode: "reject";
|
|
57
|
+
fallbackMessage: string;
|
|
58
|
+
maxDurationSeconds?: number;
|
|
59
|
+
maxBytes?: number;
|
|
60
|
+
}
|
|
61
|
+
| {
|
|
62
|
+
mode: "transcribe";
|
|
63
|
+
fallbackMessage: string;
|
|
64
|
+
maxDurationSeconds?: number;
|
|
65
|
+
maxBytes?: number;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type AgentTranscriptionLimits = {
|
|
69
|
+
maxDurationSeconds?: number;
|
|
70
|
+
maxBytes?: number;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export type AgentTranscriptionConfig = {
|
|
74
|
+
provider: TranscriptionProviderName;
|
|
75
|
+
model: string;
|
|
76
|
+
secret?: string;
|
|
77
|
+
language?: string;
|
|
78
|
+
prompt?: string;
|
|
79
|
+
limits?: AgentTranscriptionLimits;
|
|
80
|
+
rawAudioTtlSeconds?: number;
|
|
81
|
+
};
|
|
82
|
+
|
|
42
83
|
export type WebsiteChannelAccess = {
|
|
43
84
|
mode: "token";
|
|
44
85
|
};
|
|
@@ -49,6 +90,7 @@ export type WebsiteChannelInput = {
|
|
|
49
90
|
secrets?: string[];
|
|
50
91
|
limits?: ChannelLimits;
|
|
51
92
|
buffer?: ChannelBufferInput;
|
|
93
|
+
audio?: ChannelAudioInput;
|
|
52
94
|
};
|
|
53
95
|
|
|
54
96
|
export type WebsiteChannelConfig = {
|
|
@@ -59,6 +101,7 @@ export type WebsiteChannelConfig = {
|
|
|
59
101
|
secrets: string[];
|
|
60
102
|
limits?: ChannelLimits;
|
|
61
103
|
buffer?: ChannelBufferConfig;
|
|
104
|
+
audio?: ChannelAudioConfig;
|
|
62
105
|
};
|
|
63
106
|
|
|
64
107
|
export type TelegramChannelInput = {
|
|
@@ -67,6 +110,7 @@ export type TelegramChannelInput = {
|
|
|
67
110
|
allowedUpdates?: TelegramAllowedUpdate[];
|
|
68
111
|
limits?: ChannelLimits;
|
|
69
112
|
buffer?: ChannelBufferInput;
|
|
113
|
+
audio?: ChannelAudioInput;
|
|
70
114
|
};
|
|
71
115
|
|
|
72
116
|
export type TelegramChannelConfig = {
|
|
@@ -77,6 +121,7 @@ export type TelegramChannelConfig = {
|
|
|
77
121
|
allowedUpdates: TelegramAllowedUpdate[];
|
|
78
122
|
limits?: ChannelLimits;
|
|
79
123
|
buffer?: ChannelBufferConfig;
|
|
124
|
+
audio?: ChannelAudioConfig;
|
|
80
125
|
};
|
|
81
126
|
|
|
82
127
|
export type WhatsappChannelInput = {
|
|
@@ -85,6 +130,7 @@ export type WhatsappChannelInput = {
|
|
|
85
130
|
secrets?: string[];
|
|
86
131
|
limits?: ChannelLimits;
|
|
87
132
|
buffer?: ChannelBufferInput;
|
|
133
|
+
audio?: ChannelAudioInput;
|
|
88
134
|
};
|
|
89
135
|
|
|
90
136
|
export type WhatsappChannelConfig = {
|
|
@@ -94,10 +140,35 @@ export type WhatsappChannelConfig = {
|
|
|
94
140
|
secrets: string[];
|
|
95
141
|
limits?: ChannelLimits;
|
|
96
142
|
buffer?: ChannelBufferConfig;
|
|
143
|
+
audio?: ChannelAudioConfig;
|
|
97
144
|
};
|
|
98
145
|
|
|
99
146
|
export type AgentChannel = WebsiteChannelConfig | TelegramChannelConfig | WhatsappChannelConfig;
|
|
100
147
|
|
|
148
|
+
export type IntegrationTagsConfig = {
|
|
149
|
+
enable?: string[];
|
|
150
|
+
disable?: string[];
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export type ComposioManagedIntegrationInput = {
|
|
154
|
+
name?: string;
|
|
155
|
+
toolkits: string[];
|
|
156
|
+
tools?: Record<string, string[]>;
|
|
157
|
+
tags?: IntegrationTagsConfig;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export type ComposioManagedIntegration = {
|
|
161
|
+
type: "composio";
|
|
162
|
+
provider: "composio";
|
|
163
|
+
mode: "managed";
|
|
164
|
+
name: string;
|
|
165
|
+
toolkits: string[];
|
|
166
|
+
tools?: Record<string, string[]>;
|
|
167
|
+
tags?: IntegrationTagsConfig;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export type AgentIntegration = ComposioManagedIntegration;
|
|
171
|
+
|
|
101
172
|
export type AgentDatabaseConfig =
|
|
102
173
|
| {
|
|
103
174
|
driver: "none";
|
|
@@ -269,7 +340,9 @@ export type AgentConfig = {
|
|
|
269
340
|
instructions: string;
|
|
270
341
|
secrets: string[];
|
|
271
342
|
tools?: AgentTool[];
|
|
343
|
+
integrations?: AgentIntegration[];
|
|
272
344
|
channels?: AgentChannel[];
|
|
345
|
+
transcription?: AgentTranscriptionConfig;
|
|
273
346
|
knowledge?: AgentKnowledgeConfig;
|
|
274
347
|
access: {
|
|
275
348
|
mode: AccessMode;
|
|
@@ -290,6 +363,23 @@ export function defineTool<Input = unknown, Output = unknown>(tool: AgentTool<In
|
|
|
290
363
|
return tool;
|
|
291
364
|
}
|
|
292
365
|
|
|
366
|
+
export function composioManaged(input: ComposioManagedIntegrationInput): ComposioManagedIntegration {
|
|
367
|
+
const name = normalizeIntegrationName(input.name ?? "composio", "composio integration name");
|
|
368
|
+
const toolkits = normalizeToolkitList(input.toolkits, "composioManaged.toolkits");
|
|
369
|
+
const tools = input.tools ? normalizeComposioToolMap(input.tools, toolkits) : undefined;
|
|
370
|
+
const tags = input.tags ? normalizeIntegrationTags(input.tags) : undefined;
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
type: "composio",
|
|
374
|
+
provider: "composio",
|
|
375
|
+
mode: "managed",
|
|
376
|
+
name,
|
|
377
|
+
toolkits,
|
|
378
|
+
...(tools ? { tools } : {}),
|
|
379
|
+
...(tags ? { tags } : {}),
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
293
383
|
export function websiteChannel(input: WebsiteChannelInput): WebsiteChannelConfig {
|
|
294
384
|
return {
|
|
295
385
|
type: "website",
|
|
@@ -299,6 +389,7 @@ export function websiteChannel(input: WebsiteChannelInput): WebsiteChannelConfig
|
|
|
299
389
|
secrets: normalizeChannelSecrets(input.secrets ?? ["AGENTKIT_WEBSITE_CHANNEL_TOKEN"], "website channel"),
|
|
300
390
|
...(input.limits ? { limits: input.limits } : {}),
|
|
301
391
|
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "website channel") } : {}),
|
|
392
|
+
...(input.audio ? { audio: normalizeChannelAudio(input.audio, "website channel") } : {}),
|
|
302
393
|
};
|
|
303
394
|
}
|
|
304
395
|
|
|
@@ -314,6 +405,7 @@ export function telegramChannel(input: TelegramChannelInput): TelegramChannelCon
|
|
|
314
405
|
allowedUpdates: input.allowedUpdates ?? ["message"],
|
|
315
406
|
...(input.limits ? { limits: input.limits } : {}),
|
|
316
407
|
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "telegram channel") } : {}),
|
|
408
|
+
...(input.audio ? { audio: normalizeChannelAudio(input.audio, "telegram channel") } : {}),
|
|
317
409
|
};
|
|
318
410
|
}
|
|
319
411
|
|
|
@@ -328,6 +420,7 @@ export function whatsappChannel(input: WhatsappChannelInput): WhatsappChannelCon
|
|
|
328
420
|
),
|
|
329
421
|
...(input.limits ? { limits: input.limits } : {}),
|
|
330
422
|
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, `${input.provider} whatsapp channel`) } : {}),
|
|
423
|
+
...(input.audio ? { audio: normalizeChannelAudio(input.audio, `${input.provider} whatsapp channel`) } : {}),
|
|
331
424
|
};
|
|
332
425
|
}
|
|
333
426
|
|
|
@@ -353,6 +446,109 @@ function normalizeChannelSecrets(secrets: string[], context: string): string[] {
|
|
|
353
446
|
return Array.from(uniqueSecrets).sort();
|
|
354
447
|
}
|
|
355
448
|
|
|
449
|
+
function normalizeIntegrationName(value: string, context: string): string {
|
|
450
|
+
const name = value.trim();
|
|
451
|
+
|
|
452
|
+
if (!/^[a-z][a-z0-9-]*$/.test(name)) {
|
|
453
|
+
throw new Error(`${context} must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return name;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function normalizeToolkitList(values: string[], context: string): string[] {
|
|
460
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
461
|
+
throw new Error(`${context} must include at least one toolkit slug.`);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const toolkits = new Set<string>();
|
|
465
|
+
|
|
466
|
+
for (const value of values) {
|
|
467
|
+
if (typeof value !== "string") {
|
|
468
|
+
throw new Error(`${context} entries must be toolkit slug strings.`);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const toolkit = value.trim().toLowerCase();
|
|
472
|
+
|
|
473
|
+
if (!/^[a-z][a-z0-9_-]*$/.test(toolkit)) {
|
|
474
|
+
throw new Error(`${context} entries must start with a letter and contain only letters, numbers, underscores, and hyphens.`);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
toolkits.add(toolkit);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return Array.from(toolkits).sort();
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function normalizeComposioToolMap(values: Record<string, string[]>, toolkits: string[]): Record<string, string[]> | undefined {
|
|
484
|
+
const toolkitSet = new Set(toolkits);
|
|
485
|
+
const normalized: Record<string, string[]> = {};
|
|
486
|
+
|
|
487
|
+
for (const [rawToolkit, rawTools] of Object.entries(values)) {
|
|
488
|
+
const toolkit = rawToolkit.trim().toLowerCase();
|
|
489
|
+
|
|
490
|
+
if (!toolkitSet.has(toolkit)) {
|
|
491
|
+
throw new Error(`composioManaged.tools.${rawToolkit} must reference a toolkit listed in composioManaged.toolkits.`);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (!Array.isArray(rawTools) || rawTools.length === 0) {
|
|
495
|
+
throw new Error(`composioManaged.tools.${rawToolkit} must include at least one Composio action slug.`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const tools = new Set<string>();
|
|
499
|
+
|
|
500
|
+
for (const rawTool of rawTools) {
|
|
501
|
+
if (typeof rawTool !== "string") {
|
|
502
|
+
throw new Error(`composioManaged.tools.${rawToolkit} entries must be Composio action slug strings.`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const tool = rawTool.trim().toUpperCase();
|
|
506
|
+
|
|
507
|
+
if (!/^[A-Z][A-Z0-9_]*$/.test(tool)) {
|
|
508
|
+
throw new Error(`composioManaged.tools.${rawToolkit} entries must be uppercase Composio action slugs.`);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
tools.add(tool);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
normalized[toolkit] = Array.from(tools).sort();
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return Object.keys(normalized).length > 0 ? normalized : undefined;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function normalizeIntegrationTags(tags: IntegrationTagsConfig): IntegrationTagsConfig {
|
|
521
|
+
const normalized: IntegrationTagsConfig = {};
|
|
522
|
+
|
|
523
|
+
if (tags.enable !== undefined) {
|
|
524
|
+
normalized.enable = normalizeTagList(tags.enable, "composioManaged.tags.enable");
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (tags.disable !== undefined) {
|
|
528
|
+
normalized.disable = normalizeTagList(tags.disable, "composioManaged.tags.disable");
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
return normalized;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function normalizeTagList(values: string[], context: string): string[] {
|
|
535
|
+
if (!Array.isArray(values)) {
|
|
536
|
+
throw new Error(`${context} must be an array of tag strings.`);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return Array.from(
|
|
540
|
+
new Set(
|
|
541
|
+
values.map((value) => {
|
|
542
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
543
|
+
throw new Error(`${context} entries must be non-empty strings.`);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return value.trim();
|
|
547
|
+
}),
|
|
548
|
+
),
|
|
549
|
+
).sort();
|
|
550
|
+
}
|
|
551
|
+
|
|
356
552
|
function normalizeChannelBuffer(input: ChannelBufferInput, context: string): ChannelBufferConfig {
|
|
357
553
|
if (input.mode === "off") {
|
|
358
554
|
return { mode: "off" };
|
|
@@ -382,6 +578,33 @@ function normalizeChannelBuffer(input: ChannelBufferInput, context: string): Cha
|
|
|
382
578
|
return buffer;
|
|
383
579
|
}
|
|
384
580
|
|
|
581
|
+
function normalizeChannelAudio(input: ChannelAudioInput, context: string): ChannelAudioConfig {
|
|
582
|
+
const mode = input.mode ?? "transcribe";
|
|
583
|
+
|
|
584
|
+
if (mode !== "off" && mode !== "reject" && mode !== "transcribe") {
|
|
585
|
+
throw new Error(`${context} audio.mode must be "off", "reject", or "transcribe".`);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (mode === "off") {
|
|
589
|
+
return { mode: "off" };
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (input.maxDurationSeconds !== undefined) {
|
|
593
|
+
validatePositiveInteger(input.maxDurationSeconds, `${context} audio.maxDurationSeconds`);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (input.maxBytes !== undefined) {
|
|
597
|
+
validatePositiveInteger(input.maxBytes, `${context} audio.maxBytes`);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return {
|
|
601
|
+
mode,
|
|
602
|
+
fallbackMessage: input.fallbackMessage ?? "I received an audio message, but I could not transcribe it. Please send the message as text.",
|
|
603
|
+
...(input.maxDurationSeconds !== undefined ? { maxDurationSeconds: input.maxDurationSeconds } : {}),
|
|
604
|
+
...(input.maxBytes !== undefined ? { maxBytes: input.maxBytes } : {}),
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
385
608
|
function validatePositiveInteger(value: number, field: string): void {
|
|
386
609
|
if (!Number.isInteger(value) || value <= 0) {
|
|
387
610
|
throw new Error(`${field} must be a positive integer.`);
|
|
@@ -413,10 +636,13 @@ export { AgentKitError } from "./runtime/errors";
|
|
|
413
636
|
export type {
|
|
414
637
|
ChannelAdapter,
|
|
415
638
|
ChannelAdapterId,
|
|
639
|
+
ChannelAudioAttachment,
|
|
416
640
|
ChannelDeliveryDirection,
|
|
417
641
|
ChannelDeliveryState,
|
|
418
642
|
ChannelEventKind,
|
|
419
643
|
ChannelExternalIdentity,
|
|
644
|
+
ChannelMediaDownloadInput,
|
|
645
|
+
ChannelMediaDownloadResult,
|
|
420
646
|
ChannelMessageContentType,
|
|
421
647
|
ChannelMessageRole,
|
|
422
648
|
ChannelSendInput,
|
|
@@ -429,3 +655,8 @@ export type {
|
|
|
429
655
|
WebhookVerificationInput,
|
|
430
656
|
WebhookVerificationResult,
|
|
431
657
|
} from "./runtime/channels";
|
|
658
|
+
export type {
|
|
659
|
+
TranscriptionAdapter,
|
|
660
|
+
TranscriptionInput,
|
|
661
|
+
TranscriptionResult,
|
|
662
|
+
} from "./runtime/transcription";
|
|
@@ -8,9 +8,11 @@ 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
17
|
| "zapster-unsupported-media";
|
|
16
18
|
|