@andreprado/agentkit 0.1.1 → 0.3.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 +8 -77
- package/docs/guides/add-channel.md +14 -92
- package/docs/guides/add-knowledge.md +0 -21
- package/docs/guides/add-tool.md +5 -11
- package/docs/guides/channel-security.md +3 -207
- package/docs/guides/connect-discord.md +7 -172
- package/docs/guides/connect-slack.md +6 -121
- package/docs/guides/connect-telegram.md +6 -165
- package/docs/guides/connect-whatsapp-evolution.md +6 -116
- package/docs/guides/connect-whatsapp-uazapi.md +6 -134
- package/docs/guides/connect-whatsapp-zapster.md +6 -202
- package/docs/guides/create-agent.md +5 -14
- package/docs/guides/debug-channel.md +4 -156
- package/docs/guides/improve-local.md +13 -0
- package/docs/guides/local-only-migration.md +35 -0
- package/docs/guides/replay-local-traces.md +11 -0
- package/docs/guides/run-evals.md +2 -4
- package/docs/guides/security-rules.md +5 -154
- package/docs/guides/use-jev.md +3 -6
- package/docs/guides/use-provider.md +5 -6
- package/docs/guides/write-feedback.md +10 -0
- package/docs/llms-full.txt +27 -448
- package/docs/llms.txt +8 -44
- package/package.json +3 -5
- package/src/cli/commands/channels.ts +8 -1613
- package/src/cli/commands/feedback.ts +8 -86
- package/src/cli/commands/provider.ts +29 -11
- package/src/cli/constants.ts +0 -3
- package/src/cli/flags.ts +0 -28
- package/src/cli/help.ts +16 -92
- package/src/cli/index.ts +15 -1091
- package/src/index.ts +6 -158
- package/src/providers/codex-auth.ts +16 -2
- package/src/providers/pi.ts +36 -19
- package/src/runtime/channels/discord.ts +2 -2
- package/src/runtime/chat.ts +5 -3
- package/src/runtime/config.ts +14 -148
- package/src/runtime/database.ts +2 -2
- package/src/runtime/dev-server.ts +8 -8
- package/src/runtime/env.ts +11 -0
- package/src/runtime/improve.ts +2 -262
- package/src/runtime/inspect.ts +13 -73
- package/src/runtime/knowledge/ingest.ts +1 -1
- package/src/runtime/knowledge/tool.ts +16 -2
- package/src/runtime/knowledge/vector.ts +1 -1
- package/src/runtime/tool-runner.ts +5 -3
- package/src/runtime/tools.ts +10 -14
- package/src/storage/sqlite.ts +11 -32
- package/src/templates/blank.ts +15 -102
- package/src/templates/common.ts +60 -0
- package/src/templates/dentista.ts +7 -74
- package/src/templates/skills/agentkit-capsule/SKILL.md +5 -7
- package/src/templates/skills/agentkit-capsule/references/docs-router.md +2 -3
- package/src/templates/skills/agentkit-channels/SKILL.md +6 -119
- package/src/templates/skills/agentkit-channels/references/channel-buffering.md +0 -9
- package/src/templates/skills/agentkit-channels/references/channel-debugging.md +1 -64
- package/src/templates/skills/agentkit-channels/references/discord.md +2 -92
- package/src/templates/skills/agentkit-channels/references/slack.md +2 -55
- package/src/templates/skills/agentkit-channels/references/telegram.md +2 -71
- package/src/templates/skills/agentkit-channels/references/whatsapp-evolution.md +2 -56
- package/src/templates/skills/agentkit-channels/references/whatsapp-uazapi.md +2 -53
- package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +2 -70
- package/src/templates/skills/agentkit-database/SKILL.md +2 -4
- package/src/templates/skills/agentkit-evals/SKILL.md +1 -1
- package/src/templates/skills/agentkit-improve/SKILL.md +6 -85
- package/src/templates/skills/agentkit-improve/references/trace-packets.md +1 -1
- package/src/templates/skills/agentkit-provider/SKILL.md +1 -2
- package/src/templates/skills/agentkit-security/SKILL.md +1 -3
- package/src/templates/skills/agentkit-tools/SKILL.md +1 -1
- package/src/templates/skills/agentkit-tools/examples/database-write.tool.md +1 -2
- package/src/templates/skills/agentkit-troubleshooting/SKILL.md +5 -11
- package/src/templates/support.ts +8 -92
- package/docs/guides/add-managed-composio.md +0 -165
- package/docs/guides/improve-from-production.md +0 -151
- package/docs/guides/prepare-deploy.md +0 -227
- package/docs/guides/replay-production-traces.md +0 -72
- package/docs/guides/send-feedback.md +0 -135
- package/src/cli/cloud-client.ts +0 -377
- package/src/cli/deploy-chat-ui.ts +0 -606
- package/src/cli/deploy-readiness.ts +0 -561
- package/src/cloud/artifact.ts +0 -139
- package/src/cloud/client.ts +0 -80
- package/src/cloud/contracts.ts +0 -63
- package/src/cloud/index.ts +0 -3
- package/src/runtime/build.ts +0 -43
- package/src/runtime/core/deploy-state.ts +0 -54
- package/src/runtime/core/manifest.ts +0 -283
- package/src/runtime/core/targets.ts +0 -133
- package/src/runtime/deploy-readiness.ts +0 -135
- package/src/runtime/deploy.ts +0 -1
- package/src/runtime/integrations/composio.ts +0 -425
- package/src/runtime/targets/cloudflare/build.ts +0 -3319
- package/src/runtime/targets/container/build.ts +0 -146
- package/src/runtime/targets/container/server.ts +0 -33
- package/src/runtime/targets/vps/deploy.ts +0 -223
- package/src/templates/skills/agentkit-deploy/SKILL.md +0 -52
- package/src/templates/skills/agentkit-integrations/SKILL.md +0 -98
|
@@ -1,561 +0,0 @@
|
|
|
1
|
-
import { findAgentCapsuleRoot, loadAgentCapsule } from "../runtime/config";
|
|
2
|
-
import { loadDeployReadinessContext, type DeployReadinessContext } from "../runtime/deploy-readiness";
|
|
3
|
-
import { loadCapsuleEnv } from "../runtime/env";
|
|
4
|
-
import { isAgentKitError } from "../runtime/errors";
|
|
5
|
-
import { MANAGED_COMPOSIO_API_KEY_SECRET, MANAGED_COMPOSIO_ENTITLEMENT } from "../runtime/integrations/composio";
|
|
6
|
-
import {
|
|
7
|
-
cloudApiRequest,
|
|
8
|
-
formatCloudAuthSource,
|
|
9
|
-
readCloudAuthForApiUrl,
|
|
10
|
-
type CloudCapabilitiesResponse,
|
|
11
|
-
type CloudLimitsResponse,
|
|
12
|
-
type CloudManagedComposioResponse,
|
|
13
|
-
type CloudMeResponse,
|
|
14
|
-
type CloudProjectResolveResponse,
|
|
15
|
-
type CloudSecretsResponse,
|
|
16
|
-
} from "./cloud-client";
|
|
17
|
-
|
|
18
|
-
type DeployReadinessStatus = "pass" | "fail" | "warn" | "info";
|
|
19
|
-
|
|
20
|
-
type DeployReadinessCheck = {
|
|
21
|
-
status: DeployReadinessStatus;
|
|
22
|
-
title: string;
|
|
23
|
-
message: string;
|
|
24
|
-
action?: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type DeployReadinessReport = {
|
|
28
|
-
ok: boolean;
|
|
29
|
-
apiUrl: string;
|
|
30
|
-
context: DeployReadinessContext;
|
|
31
|
-
checks: DeployReadinessCheck[];
|
|
32
|
-
cloudAuth: {
|
|
33
|
-
source?: string;
|
|
34
|
-
accountEmail?: string;
|
|
35
|
-
};
|
|
36
|
-
onlineCapacity: {
|
|
37
|
-
accountUsed?: number;
|
|
38
|
-
accountLimit?: number;
|
|
39
|
-
globalUsed?: number;
|
|
40
|
-
globalLimit?: number;
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export async function checkDeployReadiness(options: {
|
|
45
|
-
apiUrl: string;
|
|
46
|
-
requireLogin: boolean;
|
|
47
|
-
}): Promise<DeployReadinessReport> {
|
|
48
|
-
const context = await loadDeployReadinessContext(process.cwd(), process.env);
|
|
49
|
-
const auth = options.requireLogin ? await readCloudAuthForApiUrl(options.apiUrl) : null;
|
|
50
|
-
const checks: DeployReadinessCheck[] = [];
|
|
51
|
-
let cloudAuthUsable = false;
|
|
52
|
-
const cloudAuth: DeployReadinessReport["cloudAuth"] = {};
|
|
53
|
-
const onlineCapacity: DeployReadinessReport["onlineCapacity"] = {};
|
|
54
|
-
|
|
55
|
-
if (auth?.token) {
|
|
56
|
-
cloudAuth.source = formatCloudAuthSource(auth);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (context.runtime !== "edge") {
|
|
60
|
-
checks.push({
|
|
61
|
-
status: "fail",
|
|
62
|
-
title: "Target runtime",
|
|
63
|
-
message: 'Cloudflare deploy requires runtime: "edge" in agentkit.config.ts.',
|
|
64
|
-
action: "set runtime: \"edge\" before deploying to AgentKit Cloud",
|
|
65
|
-
});
|
|
66
|
-
} else {
|
|
67
|
-
checks.push({
|
|
68
|
-
status: "pass",
|
|
69
|
-
title: "Target runtime",
|
|
70
|
-
message: "Capsule is configured for edge deploy.",
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const nodeMajor = majorNodeVersion(process.versions.node);
|
|
75
|
-
if (nodeMajor !== null && nodeMajor < 24) {
|
|
76
|
-
checks.push({
|
|
77
|
-
status: "warn",
|
|
78
|
-
title: "Node version",
|
|
79
|
-
message: `@andreprado/agentkit requires Node >=24; current Node is ${process.versions.node}.`,
|
|
80
|
-
action: "use Node 24+ before running direct node imports or production container commands",
|
|
81
|
-
});
|
|
82
|
-
} else {
|
|
83
|
-
checks.push({
|
|
84
|
-
status: "pass",
|
|
85
|
-
title: "Node version",
|
|
86
|
-
message: `Node ${process.versions.node} satisfies @andreprado/agentkit engines.node >=24.`,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (!auth?.token) {
|
|
91
|
-
checks.push({
|
|
92
|
-
status: options.requireLogin ? "fail" : "warn",
|
|
93
|
-
title: "Login",
|
|
94
|
-
message: options.requireLogin
|
|
95
|
-
? "No AgentKit Cloud token was found for hosted production deploy."
|
|
96
|
-
: "No AgentKit Cloud token was found; deploy will request anonymous mode.",
|
|
97
|
-
action: "agentkit login --token <token>",
|
|
98
|
-
});
|
|
99
|
-
} else {
|
|
100
|
-
try {
|
|
101
|
-
const me = (await cloudApiRequest(options.apiUrl, "/v1/me", { method: "GET" })) as CloudMeResponse;
|
|
102
|
-
const email = me.account?.email;
|
|
103
|
-
if (email) {
|
|
104
|
-
cloudAuth.accountEmail = email;
|
|
105
|
-
}
|
|
106
|
-
checks.push({
|
|
107
|
-
status: "pass",
|
|
108
|
-
title: "Login",
|
|
109
|
-
message: email ? `Authenticated as ${email}.` : "AgentKit Cloud token is accepted.",
|
|
110
|
-
});
|
|
111
|
-
cloudAuthUsable = true;
|
|
112
|
-
} catch (error) {
|
|
113
|
-
checks.push({
|
|
114
|
-
status: "fail",
|
|
115
|
-
title: "Login",
|
|
116
|
-
message: `AgentKit Cloud rejected the token from ${formatCloudAuthSource(auth)}. ${formatReadinessError(error)}`,
|
|
117
|
-
action: "agentkit login --token <token>",
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (cloudAuthUsable) {
|
|
123
|
-
try {
|
|
124
|
-
context.projectId = await resolveCloudProjectId(options.apiUrl, context.projectName);
|
|
125
|
-
} catch (error) {
|
|
126
|
-
checks.push({
|
|
127
|
-
status: "fail",
|
|
128
|
-
title: "Project identity",
|
|
129
|
-
message: `Could not resolve the account-scoped AgentKit Cloud project. ${formatReadinessError(error)}`,
|
|
130
|
-
});
|
|
131
|
-
cloudAuthUsable = false;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (cloudAuthUsable) {
|
|
136
|
-
try {
|
|
137
|
-
const payload = (await cloudApiRequest(options.apiUrl, "/v1/me/capabilities", {
|
|
138
|
-
method: "GET",
|
|
139
|
-
})) as CloudCapabilitiesResponse;
|
|
140
|
-
const capabilities = payload.capabilities ?? [];
|
|
141
|
-
const hasCloudflareAlpha = capabilities.some(
|
|
142
|
-
(capability) => capability.name === "cloudflare_deploy_alpha" && capability.status === "active",
|
|
143
|
-
);
|
|
144
|
-
const hasManagedComposio = capabilities.some(
|
|
145
|
-
(capability) => capability.name === MANAGED_COMPOSIO_ENTITLEMENT && capability.status === "active",
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
checks.push({
|
|
149
|
-
status: hasCloudflareAlpha ? "pass" : "fail",
|
|
150
|
-
title: "Deploy entitlement",
|
|
151
|
-
message: hasCloudflareAlpha
|
|
152
|
-
? "cloudflare_deploy_alpha is active."
|
|
153
|
-
: "This account is missing the cloudflare_deploy_alpha entitlement.",
|
|
154
|
-
...(hasCloudflareAlpha ? {} : { action: "log in with an invited AgentKit Cloud alpha token" }),
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
if (context.integrations.managedComposio.enabled) {
|
|
158
|
-
checks.push({
|
|
159
|
-
status: hasManagedComposio ? "pass" : "fail",
|
|
160
|
-
title: "Managed Composio entitlement",
|
|
161
|
-
message: hasManagedComposio
|
|
162
|
-
? `${MANAGED_COMPOSIO_ENTITLEMENT} is active.`
|
|
163
|
-
: `This capsule uses AgentKit-managed Composio, but this account is missing ${MANAGED_COMPOSIO_ENTITLEMENT}.`,
|
|
164
|
-
...(hasManagedComposio ? {} : { action: "upgrade the AgentKit Cloud account or ask an operator to grant managed_composio" }),
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
} catch (error) {
|
|
168
|
-
checks.push({
|
|
169
|
-
status: "fail",
|
|
170
|
-
title: "Deploy entitlement",
|
|
171
|
-
message: `Could not verify AgentKit Cloud capabilities. ${formatReadinessError(error)}`,
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
const payload = (await cloudApiRequest(options.apiUrl, "/v1/me/limits", {
|
|
177
|
-
method: "GET",
|
|
178
|
-
})) as CloudLimitsResponse;
|
|
179
|
-
const account = payload.online_agents?.account;
|
|
180
|
-
const global = payload.online_agents?.global;
|
|
181
|
-
const accountLimit = normalizeOptionalNumber(account?.limit);
|
|
182
|
-
const accountUsed = normalizeOptionalNumber(account?.used);
|
|
183
|
-
const globalLimit = normalizeOptionalNumber(global?.limit);
|
|
184
|
-
const globalUsed = normalizeOptionalNumber(global?.used);
|
|
185
|
-
|
|
186
|
-
if (accountLimit !== undefined) {
|
|
187
|
-
onlineCapacity.accountLimit = accountLimit;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (accountUsed !== undefined) {
|
|
191
|
-
onlineCapacity.accountUsed = accountUsed;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (globalLimit !== undefined) {
|
|
195
|
-
onlineCapacity.globalLimit = globalLimit;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (globalUsed !== undefined) {
|
|
199
|
-
onlineCapacity.globalUsed = globalUsed;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (accountLimit !== undefined && accountUsed !== undefined && accountUsed >= accountLimit) {
|
|
203
|
-
checks.push({
|
|
204
|
-
status: "fail",
|
|
205
|
-
title: "Online agent capacity",
|
|
206
|
-
message: `This account is already using ${accountUsed}/${accountLimit} online AgentKit deploys.`,
|
|
207
|
-
action: "agentkit deploy pause",
|
|
208
|
-
});
|
|
209
|
-
} else if (globalLimit !== undefined && globalUsed !== undefined && globalUsed >= globalLimit) {
|
|
210
|
-
checks.push({
|
|
211
|
-
status: "fail",
|
|
212
|
-
title: "Online agent capacity",
|
|
213
|
-
message: `AgentKit Cloud is already using ${globalUsed}/${globalLimit} global online deploy slots.`,
|
|
214
|
-
action: "agentkit deploy status",
|
|
215
|
-
});
|
|
216
|
-
} else if (accountLimit !== undefined && accountUsed !== undefined) {
|
|
217
|
-
checks.push({
|
|
218
|
-
status: "pass",
|
|
219
|
-
title: "Online agent capacity",
|
|
220
|
-
message: `Account has capacity: ${accountUsed}/${accountLimit} online deploys are in use.`,
|
|
221
|
-
});
|
|
222
|
-
} else if (globalLimit !== undefined && globalUsed !== undefined) {
|
|
223
|
-
checks.push({
|
|
224
|
-
status: "pass",
|
|
225
|
-
title: "Online agent capacity",
|
|
226
|
-
message: `Global capacity is available: ${globalUsed}/${globalLimit} online deploys are in use.`,
|
|
227
|
-
});
|
|
228
|
-
} else {
|
|
229
|
-
checks.push({
|
|
230
|
-
status: "info",
|
|
231
|
-
title: "Online agent capacity",
|
|
232
|
-
message: "No online deploy limit is configured for this account.",
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
} catch (error) {
|
|
236
|
-
checks.push({
|
|
237
|
-
status: "warn",
|
|
238
|
-
title: "Online agent capacity",
|
|
239
|
-
message: `Could not verify online deploy capacity. ${formatReadinessError(error)}`,
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (context.integrations.managedComposio.enabled) {
|
|
244
|
-
try {
|
|
245
|
-
const payload = (await cloudApiRequest(
|
|
246
|
-
options.apiUrl,
|
|
247
|
-
`/v1/me/managed-composio?toolkits=${encodeURIComponent(context.integrations.managedComposio.toolkits.join(","))}`,
|
|
248
|
-
{
|
|
249
|
-
method: "GET",
|
|
250
|
-
},
|
|
251
|
-
)) as CloudManagedComposioResponse;
|
|
252
|
-
const managed = payload.managed_composio;
|
|
253
|
-
const missingToolkits = (managed?.toolkits ?? []).filter((toolkit) => toolkit.auth_config !== "set");
|
|
254
|
-
|
|
255
|
-
if (managed?.api_key !== "set") {
|
|
256
|
-
checks.push({
|
|
257
|
-
status: "fail",
|
|
258
|
-
title: "Managed Composio API key",
|
|
259
|
-
message: `AgentKit Cloud is missing AGENTKIT_SECRET_${MANAGED_COMPOSIO_API_KEY_SECRET}.`,
|
|
260
|
-
action: "ask the AgentKit Cloud operator to configure managed Composio",
|
|
261
|
-
});
|
|
262
|
-
} else {
|
|
263
|
-
checks.push({
|
|
264
|
-
status: "pass",
|
|
265
|
-
title: "Managed Composio API key",
|
|
266
|
-
message: "AgentKit Cloud has the managed COMPOSIO_API_KEY.",
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (missingToolkits.length > 0) {
|
|
271
|
-
checks.push({
|
|
272
|
-
status: "fail",
|
|
273
|
-
title: "Managed Composio auth configs",
|
|
274
|
-
message: `Missing ${missingToolkits
|
|
275
|
-
.map((toolkit) => `${toolkit.auth_config_env ?? "auth config"} for ${toolkit.toolkit ?? "unknown"}`)
|
|
276
|
-
.join(", ")}.`,
|
|
277
|
-
action: "ask the AgentKit Cloud operator to configure the Composio auth config registry or fallback env",
|
|
278
|
-
});
|
|
279
|
-
} else {
|
|
280
|
-
const toolkitSources = (managed?.toolkits ?? []).map((toolkit) =>
|
|
281
|
-
`${toolkit.toolkit ?? "unknown"}${toolkit.auth_config_source ? ` via ${toolkit.auth_config_source}` : ""}`,
|
|
282
|
-
);
|
|
283
|
-
checks.push({
|
|
284
|
-
status: "pass",
|
|
285
|
-
title: "Managed Composio auth configs",
|
|
286
|
-
message: `Auth configs are available for ${toolkitSources.join(", ")}.`,
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
} catch (error) {
|
|
290
|
-
checks.push({
|
|
291
|
-
status: "warn",
|
|
292
|
-
title: "Managed Composio auth configs",
|
|
293
|
-
message: `Could not verify managed Composio auth configs. ${formatReadinessError(error)}`,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (context.agentKitManagedSecrets.length > 0) {
|
|
300
|
-
checks.push({
|
|
301
|
-
status: "info",
|
|
302
|
-
title: "AgentKit-managed secrets",
|
|
303
|
-
message: `${context.agentKitManagedSecrets.join(", ")} ${
|
|
304
|
-
context.agentKitManagedSecrets.length === 1 ? "is" : "are"
|
|
305
|
-
} provisioned by AgentKit Cloud during deploy.`,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (context.integrations.managedComposio.enabled) {
|
|
310
|
-
if (!options.requireLogin) {
|
|
311
|
-
checks.push({
|
|
312
|
-
status: "fail",
|
|
313
|
-
title: "Managed Composio access",
|
|
314
|
-
message: "AgentKit-managed Composio is paid hosted infrastructure and cannot be used by anonymous deploys.",
|
|
315
|
-
action: "run agentkit deploy without --anonymous after logging in with a paid AgentKit Cloud account",
|
|
316
|
-
});
|
|
317
|
-
} else {
|
|
318
|
-
checks.push({
|
|
319
|
-
status: "info",
|
|
320
|
-
title: "Managed Composio",
|
|
321
|
-
message: `Configured for ${context.integrations.managedComposio.toolkits.join(", ")} with ${
|
|
322
|
-
context.integrations.managedComposio.toolCount
|
|
323
|
-
} allowed action${context.integrations.managedComposio.toolCount === 1 ? "" : "s"}. AgentKit Cloud injects COMPOSIO_API_KEY.`,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (context.accessMode === "private") {
|
|
329
|
-
checks.push({
|
|
330
|
-
status: "info",
|
|
331
|
-
title: "Private access",
|
|
332
|
-
message: "AGENTKIT_PRIVATE_TOKEN is required at runtime; AgentKit Cloud generates it and saves it in .agentkit/deploy.json.",
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if (context.knowledge.enabled) {
|
|
337
|
-
if (context.knowledge.databaseDriver !== "turso") {
|
|
338
|
-
checks.push({
|
|
339
|
-
status: "fail",
|
|
340
|
-
title: "Knowledge storage",
|
|
341
|
-
message: "Hosted Knowledge requires a Turso database so indexed chunks are available to the Cloudflare runtime.",
|
|
342
|
-
action: 'set storage.database.driver: "turso" in agentkit.config.ts before deploying Knowledge',
|
|
343
|
-
});
|
|
344
|
-
} else {
|
|
345
|
-
checks.push({
|
|
346
|
-
status: "pass",
|
|
347
|
-
title: "Knowledge storage",
|
|
348
|
-
message: `Knowledge is configured with ${context.knowledge.sourceCount} source${
|
|
349
|
-
context.knowledge.sourceCount === 1 ? "" : "s"
|
|
350
|
-
} and Turso storage.`,
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (context.userManagedSecrets.length === 0) {
|
|
356
|
-
checks.push({
|
|
357
|
-
status: "pass",
|
|
358
|
-
title: "Hosted secrets",
|
|
359
|
-
message: "No user-managed hosted secrets are required by this capsule.",
|
|
360
|
-
});
|
|
361
|
-
} else if (!cloudAuthUsable) {
|
|
362
|
-
checks.push({
|
|
363
|
-
status: options.requireLogin ? "fail" : "warn",
|
|
364
|
-
title: "Hosted secrets",
|
|
365
|
-
message: `Could not check hosted secrets without a valid AgentKit Cloud login. Required: ${context.userManagedSecrets.join(", ")}.`,
|
|
366
|
-
action: "agentkit secret list",
|
|
367
|
-
});
|
|
368
|
-
} else {
|
|
369
|
-
try {
|
|
370
|
-
const payload = (await cloudApiRequest(
|
|
371
|
-
options.apiUrl,
|
|
372
|
-
`/v1/projects/${encodeURIComponent(context.projectId)}/secrets`,
|
|
373
|
-
{ method: "GET" },
|
|
374
|
-
)) as CloudSecretsResponse;
|
|
375
|
-
const hostedSecretNames = new Set((payload.secrets ?? []).map((secret) => secret.name).filter(isString));
|
|
376
|
-
const missing = context.userManagedSecrets.filter((name) => !hostedSecretNames.has(name));
|
|
377
|
-
|
|
378
|
-
if (missing.length === 0) {
|
|
379
|
-
checks.push({
|
|
380
|
-
status: "pass",
|
|
381
|
-
title: "Hosted secrets",
|
|
382
|
-
message: "All user-managed hosted secrets are set.",
|
|
383
|
-
});
|
|
384
|
-
} else {
|
|
385
|
-
for (const secret of missing) {
|
|
386
|
-
const localSource = context.localSecrets[secret];
|
|
387
|
-
checks.push({
|
|
388
|
-
status: "fail",
|
|
389
|
-
title: `Hosted secret ${secret}`,
|
|
390
|
-
message: localSource
|
|
391
|
-
? `${secret} is present locally but has not been set in AgentKit Cloud.`
|
|
392
|
-
: `${secret} is required but missing from AgentKit Cloud.`,
|
|
393
|
-
action: secretSetCommand(secret, localSource),
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
} catch (error) {
|
|
398
|
-
checks.push({
|
|
399
|
-
status: "fail",
|
|
400
|
-
title: "Hosted secrets",
|
|
401
|
-
message: `Could not list hosted secrets for project ${context.projectId}. ${formatReadinessError(error)}`,
|
|
402
|
-
action: "agentkit secret list",
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return {
|
|
408
|
-
ok: checks.every((check) => check.status !== "fail"),
|
|
409
|
-
apiUrl: options.apiUrl,
|
|
410
|
-
context,
|
|
411
|
-
checks,
|
|
412
|
-
cloudAuth,
|
|
413
|
-
onlineCapacity,
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
export function printDeployReadinessReport(report: DeployReadinessReport): void {
|
|
418
|
-
console.log("AgentKit deploy readiness");
|
|
419
|
-
console.log(`Project: ${report.context.projectName}`);
|
|
420
|
-
console.log(`Project ID: ${report.context.projectId}`);
|
|
421
|
-
console.log(`Target: ${report.context.target}`);
|
|
422
|
-
console.log(`API: ${report.apiUrl}`);
|
|
423
|
-
const authSummary = formatDeployCloudAuthSummary(report);
|
|
424
|
-
|
|
425
|
-
if (authSummary) {
|
|
426
|
-
console.log(`Account: ${authSummary.account}`);
|
|
427
|
-
console.log(`Auth source: ${authSummary.source}`);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const capacitySummary = formatDeployOnlineCapacity(report, "current");
|
|
431
|
-
|
|
432
|
-
if (capacitySummary) {
|
|
433
|
-
console.log(`Capacity: ${capacitySummary}`);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
console.log("");
|
|
437
|
-
|
|
438
|
-
for (const check of report.checks) {
|
|
439
|
-
console.log(`[${check.status}] ${check.title}: ${check.message}`);
|
|
440
|
-
|
|
441
|
-
if (check.action) {
|
|
442
|
-
console.log(` Run: ${check.action}`);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
export function formatDeployCloudAuthSummary(
|
|
448
|
-
report: DeployReadinessReport,
|
|
449
|
-
): { account: string; source: string } | null {
|
|
450
|
-
if (!report.cloudAuth.accountEmail || !report.cloudAuth.source) {
|
|
451
|
-
return null;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
return {
|
|
455
|
-
account: report.cloudAuth.accountEmail,
|
|
456
|
-
source: report.cloudAuth.source,
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
export function formatDeployOnlineCapacity(
|
|
461
|
-
report: DeployReadinessReport,
|
|
462
|
-
timing: "current" | "before deploy",
|
|
463
|
-
): string | null {
|
|
464
|
-
const suffix = timing === "before deploy" ? " before deploy" : "";
|
|
465
|
-
|
|
466
|
-
if (report.onlineCapacity.accountUsed !== undefined && report.onlineCapacity.accountLimit !== undefined) {
|
|
467
|
-
return `${report.onlineCapacity.accountUsed}/${report.onlineCapacity.accountLimit} account online deploy slots in use${suffix}`;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if (report.onlineCapacity.globalUsed !== undefined && report.onlineCapacity.globalLimit !== undefined) {
|
|
471
|
-
return `${report.onlineCapacity.globalUsed}/${report.onlineCapacity.globalLimit} global online deploy slots in use${suffix}`;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
return null;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
export async function syncHostedSecretsFromLocal(options: { apiUrl: string; projectId: string }): Promise<void> {
|
|
478
|
-
const context = await loadDeployReadinessContext(process.cwd(), process.env);
|
|
479
|
-
const localEnv = await loadCapsuleEnv(context.root, {});
|
|
480
|
-
let synced = 0;
|
|
481
|
-
let skipped = 0;
|
|
482
|
-
|
|
483
|
-
for (const secret of context.userManagedSecrets) {
|
|
484
|
-
const value = localEnv[secret];
|
|
485
|
-
|
|
486
|
-
if (value === undefined) {
|
|
487
|
-
skipped += 1;
|
|
488
|
-
console.log(`${secret}\tskipped_missing_local`);
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
await cloudApiRequest(options.apiUrl, `/v1/projects/${encodeURIComponent(options.projectId)}/secrets/${encodeURIComponent(secret)}`, {
|
|
493
|
-
method: "PUT",
|
|
494
|
-
body: JSON.stringify({ value }),
|
|
495
|
-
});
|
|
496
|
-
synced += 1;
|
|
497
|
-
console.log(`${secret}\tsynced`);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
if (context.userManagedSecrets.length === 0) {
|
|
501
|
-
console.log("No user-managed hosted secrets are declared by this capsule.");
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
console.log("");
|
|
506
|
-
console.log(`${synced} synced, ${skipped} skipped`);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
export function formatReadinessError(error: unknown): string {
|
|
510
|
-
if (isAgentKitError(error)) {
|
|
511
|
-
return `${error.code}: ${error.message}`;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
return error instanceof Error ? error.message : String(error);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
export async function resolveProjectIdForSecretCommand(cwd: string, apiUrl: string): Promise<string> {
|
|
518
|
-
const root = await findAgentCapsuleRoot(cwd);
|
|
519
|
-
const capsule = await loadAgentCapsule(root);
|
|
520
|
-
return resolveCloudProjectId(apiUrl, capsule.config.name);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
async function resolveCloudProjectId(apiUrl: string, projectName: string): Promise<string> {
|
|
524
|
-
const payload = (await cloudApiRequest(apiUrl, "/v1/projects/resolve", {
|
|
525
|
-
method: "POST",
|
|
526
|
-
body: JSON.stringify({ project_name: projectName }),
|
|
527
|
-
})) as CloudProjectResolveResponse;
|
|
528
|
-
const projectId = payload.project?.id;
|
|
529
|
-
|
|
530
|
-
if (!projectId) {
|
|
531
|
-
throw new Error("AgentKit Cloud did not return a project id.");
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
return projectId;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
function secretSetCommand(secret: string, source: DeployReadinessContext["localSecrets"][string] | undefined): string {
|
|
538
|
-
if (source?.dotenv) {
|
|
539
|
-
return `npm run agentkit -- secret set ${secret} --from-local-env`;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
if (source?.environment) {
|
|
543
|
-
return `npm run agentkit -- secret set ${secret} --from-env`;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
return `npm run agentkit -- secret set ${secret} --stdin`;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
function normalizeOptionalNumber(value: number | null | undefined): number | undefined {
|
|
550
|
-
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
function majorNodeVersion(version: string): number | null {
|
|
554
|
-
const [major] = version.split(".");
|
|
555
|
-
const parsed = Number(major);
|
|
556
|
-
return Number.isInteger(parsed) ? parsed : null;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
function isString(value: unknown): value is string {
|
|
560
|
-
return typeof value === "string";
|
|
561
|
-
}
|
package/src/cloud/artifact.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { readFile, stat } from "node:fs/promises";
|
|
3
|
-
import { extname, isAbsolute, relative, resolve } from "node:path";
|
|
4
|
-
|
|
5
|
-
import type { AgentBuildResult, AgentManifestWithBundle } from "../runtime/targets/cloudflare/build";
|
|
6
|
-
import { AgentKitError } from "../runtime/errors";
|
|
7
|
-
import type { HostedDeployArtifact } from "./contracts";
|
|
8
|
-
|
|
9
|
-
const HOSTED_KNOWLEDGE_MAX_SOURCE_BYTES = 5 * 1024 * 1024;
|
|
10
|
-
const HOSTED_KNOWLEDGE_MAX_TOTAL_BYTES = 9 * 1024 * 1024;
|
|
11
|
-
const HOSTED_KNOWLEDGE_SUPPORTED_EXTENSIONS = new Set([".md", ".markdown", ".txt", ".csv"]);
|
|
12
|
-
|
|
13
|
-
export async function createHostedDeployArtifact(build: AgentBuildResult): Promise<HostedDeployArtifact> {
|
|
14
|
-
const [manifestSource, workerSource, wranglerSource] = await Promise.all([
|
|
15
|
-
readFile(build.manifestPath, "utf8"),
|
|
16
|
-
readFile(build.workerPath, "utf8"),
|
|
17
|
-
readFile(build.wranglerPath, "utf8"),
|
|
18
|
-
]);
|
|
19
|
-
const manifest = JSON.parse(manifestSource) as AgentManifestWithBundle;
|
|
20
|
-
const workerSha256 = sha256(workerSource);
|
|
21
|
-
|
|
22
|
-
if (workerSha256 !== build.bundleSha256 || workerSha256 !== manifest.bundle.sha256) {
|
|
23
|
-
throw new AgentKitError("artifact_integrity_error", "Worker SHA-256 does not match the build manifest.");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const artifact: HostedDeployArtifact = {
|
|
27
|
-
manifest,
|
|
28
|
-
worker: {
|
|
29
|
-
content_type: "application/javascript",
|
|
30
|
-
source: workerSource,
|
|
31
|
-
sha256: workerSha256,
|
|
32
|
-
},
|
|
33
|
-
wrangler: {
|
|
34
|
-
content_type: "application/json",
|
|
35
|
-
source: wranglerSource,
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
if (build.tursoSchemaPath) {
|
|
40
|
-
const source = await readFile(build.tursoSchemaPath, "utf8");
|
|
41
|
-
artifact.turso_schema = {
|
|
42
|
-
content_type: "text/sql",
|
|
43
|
-
source,
|
|
44
|
-
sha256: sha256(source),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (manifest.knowledge.enabled) {
|
|
49
|
-
artifact.knowledge_sources = await createHostedKnowledgeSources(build.root, manifest);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return artifact;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async function createHostedKnowledgeSources(
|
|
56
|
-
root: string,
|
|
57
|
-
manifest: AgentManifestWithBundle,
|
|
58
|
-
): Promise<NonNullable<HostedDeployArtifact["knowledge_sources"]>> {
|
|
59
|
-
const sources: NonNullable<HostedDeployArtifact["knowledge_sources"]>["sources"] = [];
|
|
60
|
-
let totalBytes = 0;
|
|
61
|
-
|
|
62
|
-
for (const source of manifest.knowledge.sources) {
|
|
63
|
-
if (source.kind === "url") {
|
|
64
|
-
throw new AgentKitError(
|
|
65
|
-
"artifact_knowledge_source_unsupported",
|
|
66
|
-
"Hosted deploy can automatically sync local Knowledge files only. URL Knowledge sources require a hosted ingestion connector.",
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const absolutePath = resolve(root, source.value);
|
|
71
|
-
const sourceKey = capsuleRelativePath(root, absolutePath);
|
|
72
|
-
const extension = extname(sourceKey).toLowerCase();
|
|
73
|
-
|
|
74
|
-
if (!HOSTED_KNOWLEDGE_SUPPORTED_EXTENSIONS.has(extension)) {
|
|
75
|
-
throw new AgentKitError(
|
|
76
|
-
"artifact_knowledge_source_unsupported",
|
|
77
|
-
`Knowledge source "${sourceKey}" is not supported for hosted deploy. Use .md, .txt, or .csv.`,
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const stats = await stat(absolutePath).catch((error) => {
|
|
82
|
-
throw new AgentKitError("artifact_knowledge_source_missing", `Knowledge source "${sourceKey}" was not found.`, {
|
|
83
|
-
cause: error,
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
if (!stats.isFile()) {
|
|
88
|
-
throw new AgentKitError("artifact_knowledge_source_invalid", `Knowledge source "${sourceKey}" must be a file.`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (stats.size > HOSTED_KNOWLEDGE_MAX_SOURCE_BYTES) {
|
|
92
|
-
throw new AgentKitError(
|
|
93
|
-
"artifact_knowledge_source_too_large",
|
|
94
|
-
`Knowledge source "${sourceKey}" is too large for automatic deploy sync. Keep each source under 5MB.`,
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
totalBytes += stats.size;
|
|
99
|
-
|
|
100
|
-
if (totalBytes > HOSTED_KNOWLEDGE_MAX_TOTAL_BYTES) {
|
|
101
|
-
throw new AgentKitError(
|
|
102
|
-
"artifact_knowledge_sources_too_large",
|
|
103
|
-
"Knowledge sources are too large for automatic deploy sync. Keep total packaged Knowledge under 9MB.",
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const content = await readFile(absolutePath, "utf8");
|
|
108
|
-
sources.push({
|
|
109
|
-
kind: "file",
|
|
110
|
-
source_key: sourceKey,
|
|
111
|
-
title: source.title,
|
|
112
|
-
content,
|
|
113
|
-
sha256: sha256(content),
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
content_type: "application/json",
|
|
119
|
-
sources,
|
|
120
|
-
sha256: sha256(JSON.stringify(sources)),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function capsuleRelativePath(root: string, absolutePath: string): string {
|
|
125
|
-
const relativePath = relative(root, absolutePath);
|
|
126
|
-
|
|
127
|
-
if (!relativePath || relativePath.startsWith("..") || isAbsolute(relativePath)) {
|
|
128
|
-
throw new AgentKitError(
|
|
129
|
-
"artifact_knowledge_source_outside_capsule",
|
|
130
|
-
"Knowledge source paths must stay inside the Agent Capsule.",
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return relativePath.split("\\").join("/");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function sha256(source: string): string {
|
|
138
|
-
return createHash("sha256").update(source).digest("hex");
|
|
139
|
-
}
|