@andreprado/agentkit 0.1.0-alpha.18 → 0.1.0-alpha.19
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 +3 -0
- package/docs/guides/add-channel.md +12 -6
- package/docs/guides/add-knowledge.md +10 -0
- package/docs/guides/add-managed-composio.md +4 -2
- package/docs/guides/channel-security.md +26 -2
- package/docs/guides/connect-discord.md +178 -0
- package/docs/guides/create-agent.md +13 -0
- package/docs/guides/debug-channel.md +8 -2
- package/docs/guides/improve-from-production.md +151 -0
- package/docs/guides/prepare-deploy.md +29 -8
- package/docs/guides/replay-production-traces.md +72 -0
- package/docs/guides/run-evals.md +18 -0
- package/docs/guides/security-rules.md +5 -5
- package/docs/guides/use-provider.md +11 -1
- package/docs/llms-full.txt +100 -11
- package/docs/llms.txt +17 -1
- package/package.json +1 -1
- package/src/cli/args.ts +23 -2
- package/src/cli/cloud-client.ts +63 -0
- package/src/cli/commands/channels.ts +139 -14
- package/src/cli/deploy-readiness.ts +5 -2
- package/src/cli/help.ts +26 -2
- package/src/cli/index.ts +382 -17
- package/src/create-project.ts +13 -2
- package/src/index.ts +42 -3
- package/src/providers/pi.ts +49 -15
- package/src/runtime/channel-test-harness.ts +4 -1
- package/src/runtime/channels/discord.ts +887 -0
- package/src/runtime/channels.ts +15 -0
- package/src/runtime/config.ts +35 -3
- package/src/runtime/dev-server.ts +149 -8
- package/src/runtime/evals.ts +27 -6
- package/src/runtime/improve.ts +868 -0
- package/src/runtime/knowledge/retrieve.ts +25 -5
- package/src/runtime/knowledge/schema.ts +45 -1
- package/src/runtime/runtime-contract.ts +54 -0
- package/src/runtime/targets/cloudflare/build.ts +248 -193
- package/src/runtime/targets/vps/deploy.ts +1 -1
- package/src/storage/sqlite.ts +7 -2
- package/src/templates/skills/agentkit-capsule/SKILL.md +8 -1
- package/src/templates/skills/agentkit-capsule/references/docs-router.md +1 -2
- package/src/templates/skills/agentkit-channels/SKILL.md +6 -1
- package/src/templates/skills/agentkit-channels/references/channel-debugging.md +2 -1
- package/src/templates/skills/agentkit-channels/references/discord.md +93 -0
- package/src/templates/skills/agentkit-deploy/SKILL.md +6 -0
- package/src/templates/skills/agentkit-evals/SKILL.md +12 -3
- package/src/templates/skills/agentkit-improve/SKILL.md +86 -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 +1 -0
- package/src/templates/skills/agentkit-knowledge/SKILL.md +4 -1
- package/src/templates/skills/agentkit-provider/SKILL.md +4 -1
- package/src/templates/skills/agentkit-security/SKILL.md +3 -2
- package/src/templates/skills/agentkit-troubleshooting/SKILL.md +9 -0
- package/src/templates/support.ts +4 -2
|
@@ -320,8 +320,8 @@ async function listSourceFiles(root: string): Promise<string[]> {
|
|
|
320
320
|
function findImportSpecifiers(source: string): string[] {
|
|
321
321
|
const specifiers: string[] = [];
|
|
322
322
|
const patterns = [
|
|
323
|
-
/\bimport\s+(
|
|
324
|
-
/\bexport\s+[^"'()]*?\s+from\s+["']([^"']+)["']/g,
|
|
323
|
+
/\bimport\s+(?!type\b)(?:[^"'()]*?\s+from\s+)?["']([^"']+)["']/g,
|
|
324
|
+
/\bexport\s+(?!type\b)[^"'()]*?\s+from\s+["']([^"']+)["']/g,
|
|
325
325
|
/\brequire\(\s*["']([^"']+)["']\s*\)/g,
|
|
326
326
|
/\bimport\(\s*["']([^"']+)["']\s*\)/g,
|
|
327
327
|
];
|
|
@@ -390,6 +390,8 @@ export function composioManaged(input) {
|
|
|
390
390
|
const toolkits = normalizeToolkitList(input.toolkits, "composioManaged.toolkits");
|
|
391
391
|
const tools = input.tools ? normalizeComposioToolMap(input.tools, toolkits) : undefined;
|
|
392
392
|
const tags = input.tags ? normalizeIntegrationTags(input.tags) : undefined;
|
|
393
|
+
const confirmExternalWrites =
|
|
394
|
+
input.confirmExternalWrites === undefined ? undefined : Boolean(input.confirmExternalWrites);
|
|
393
395
|
|
|
394
396
|
return {
|
|
395
397
|
type: "composio",
|
|
@@ -399,6 +401,7 @@ export function composioManaged(input) {
|
|
|
399
401
|
toolkits,
|
|
400
402
|
...(tools ? { tools } : {}),
|
|
401
403
|
...(tags ? { tags } : {}),
|
|
404
|
+
...(confirmExternalWrites === undefined ? {} : { confirmExternalWrites }),
|
|
402
405
|
};
|
|
403
406
|
}
|
|
404
407
|
|
|
@@ -437,6 +440,17 @@ export function whatsappChannel(input) {
|
|
|
437
440
|
};
|
|
438
441
|
}
|
|
439
442
|
|
|
443
|
+
export function discordChannel(input) {
|
|
444
|
+
return {
|
|
445
|
+
type: "discord",
|
|
446
|
+
provider: "discord",
|
|
447
|
+
name: input.name,
|
|
448
|
+
secrets: normalizeChannelSecrets(input.secrets ?? ["DISCORD_PUBLIC_KEY"], "discord channel"),
|
|
449
|
+
...(input.limits ? { limits: input.limits } : {}),
|
|
450
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "discord channel") } : {}),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
440
454
|
function defaultWhatsappChannelSecrets(provider) {
|
|
441
455
|
if (provider === "zapster") {
|
|
442
456
|
return ["ZAPSTER_API_KEY", "ZAPSTER_INSTANCE_ID", "ZAPSTER_WEBHOOK_ID"];
|
|
@@ -713,11 +727,17 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
713
727
|
status TEXT NOT NULL,
|
|
714
728
|
input_json TEXT NOT NULL,
|
|
715
729
|
output_json TEXT,
|
|
730
|
+
rendered_json TEXT,
|
|
716
731
|
error_message TEXT,
|
|
717
732
|
created_at TEXT NOT NULL,
|
|
718
733
|
completed_at TEXT
|
|
719
734
|
);
|
|
720
735
|
\`);
|
|
736
|
+
try {
|
|
737
|
+
this.sql.exec("ALTER TABLE tool_calls ADD COLUMN rendered_json TEXT");
|
|
738
|
+
} catch {
|
|
739
|
+
// Existing Durable Object tables either already have this column or do not need migration.
|
|
740
|
+
}
|
|
721
741
|
}
|
|
722
742
|
|
|
723
743
|
async fetch(request) {
|
|
@@ -873,7 +893,7 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
873
893
|
|
|
874
894
|
readToolCalls(runId) {
|
|
875
895
|
const rows = this.sql.exec(
|
|
876
|
-
"SELECT id, run_id, conversation_id, tool_name, visibility, status, input_json, output_json, error_message, created_at, completed_at FROM tool_calls WHERE run_id = ? ORDER BY rowid ASC",
|
|
896
|
+
"SELECT id, run_id, conversation_id, tool_name, visibility, status, input_json, output_json, rendered_json, error_message, created_at, completed_at FROM tool_calls WHERE run_id = ? ORDER BY rowid ASC",
|
|
877
897
|
runId,
|
|
878
898
|
).toArray();
|
|
879
899
|
|
|
@@ -886,6 +906,7 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
886
906
|
status: String(row.status),
|
|
887
907
|
input: parseStoredJson(row.input_json, {}),
|
|
888
908
|
output: row.output_json === null || row.output_json === undefined ? undefined : parseStoredJson(row.output_json, null),
|
|
909
|
+
rendered: row.rendered_json === null || row.rendered_json === undefined ? undefined : parseStoredJson(row.rendered_json, null),
|
|
889
910
|
errorMessage: row.error_message === null || row.error_message === undefined ? null : String(row.error_message),
|
|
890
911
|
createdAt: String(row.created_at),
|
|
891
912
|
completedAt: row.completed_at === null || row.completed_at === undefined ? null : String(row.completed_at),
|
|
@@ -943,7 +964,7 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
943
964
|
|
|
944
965
|
for (const toolCall of input.toolCalls || []) {
|
|
945
966
|
this.sql.exec(
|
|
946
|
-
"INSERT INTO tool_calls (id, run_id, conversation_id, tool_name, visibility, status, input_json, output_json, error_message, created_at, completed_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
967
|
+
"INSERT INTO tool_calls (id, run_id, conversation_id, tool_name, visibility, status, input_json, output_json, rendered_json, error_message, created_at, completed_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
947
968
|
String(toolCall.id || crypto.randomUUID()),
|
|
948
969
|
runId,
|
|
949
970
|
conversationId,
|
|
@@ -952,6 +973,7 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
952
973
|
String(toolCall.status || "completed"),
|
|
953
974
|
JSON.stringify(toolCall.input ?? {}),
|
|
954
975
|
toolCall.output === undefined ? null : JSON.stringify(toolCall.output),
|
|
976
|
+
toolCall.rendered === undefined ? null : JSON.stringify(toolCall.rendered),
|
|
955
977
|
toolCall.errorMessage ? String(toolCall.errorMessage) : null,
|
|
956
978
|
now,
|
|
957
979
|
now,
|
|
@@ -1005,6 +1027,15 @@ export default {
|
|
|
1005
1027
|
}
|
|
1006
1028
|
|
|
1007
1029
|
if (request.method === "GET" && url.pathname === "/") {
|
|
1030
|
+
const auth = await authorizeDeployAccess(request, env, {}, {
|
|
1031
|
+
notConfiguredCode: "cloud_access_not_configured",
|
|
1032
|
+
notConfiguredMessage: "Hosted AgentKit Cloud routes require a deploy access token gate.",
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
if (auth) {
|
|
1036
|
+
return auth;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1008
1039
|
return Response.json({
|
|
1009
1040
|
agent: manifest.name,
|
|
1010
1041
|
status: "ready",
|
|
@@ -1014,7 +1045,16 @@ export default {
|
|
|
1014
1045
|
}
|
|
1015
1046
|
|
|
1016
1047
|
if (request.method === "GET" && url.pathname === "/health") {
|
|
1017
|
-
|
|
1048
|
+
const auth = await authorizeDeployAccess(request, env, {}, {
|
|
1049
|
+
notConfiguredCode: "cloud_access_not_configured",
|
|
1050
|
+
notConfiguredMessage: "Hosted AgentKit Cloud routes require a deploy access token gate.",
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
if (auth) {
|
|
1054
|
+
return auth;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
return Response.json({ ok: true });
|
|
1018
1058
|
}
|
|
1019
1059
|
|
|
1020
1060
|
if (isHostedChannelWebhookPath(url.pathname)) {
|
|
@@ -1045,14 +1085,6 @@ export default {
|
|
|
1045
1085
|
return handleTool(request, env, decodeURIComponent(url.pathname.slice("/tools/".length)));
|
|
1046
1086
|
}
|
|
1047
1087
|
|
|
1048
|
-
if (request.method === "GET" && url.pathname === "/_agentkit/turso/health") {
|
|
1049
|
-
return handleTursoHealth(request, env);
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
if (request.method === "POST" && url.pathname === "/_agentkit/turso/query") {
|
|
1053
|
-
return handleTursoQuery(request, env);
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
1088
|
if (url.pathname.startsWith("/files/")) {
|
|
1057
1089
|
return handleFile(request, env, url.pathname.slice("/files/".length));
|
|
1058
1090
|
}
|
|
@@ -1063,8 +1095,8 @@ export default {
|
|
|
1063
1095
|
|
|
1064
1096
|
function isHostedChannelWebhookPath(pathname) {
|
|
1065
1097
|
return (
|
|
1066
|
-
/^\\/channels\\/[^/]+\\/(?:website\\/agentkit|telegram\\/telegram|whatsapp\\/(?:zapster|meta))\\/webhook$/.test(pathname) ||
|
|
1067
|
-
/^\\/channels\\/[^/]+\\/(?:website|telegram)\\/webhook$/.test(pathname) ||
|
|
1098
|
+
/^\\/channels\\/[^/]+\\/(?:website\\/agentkit|telegram\\/telegram|whatsapp\\/(?:zapster|meta)|discord\\/discord)\\/webhook$/.test(pathname) ||
|
|
1099
|
+
/^\\/channels\\/[^/]+\\/(?:website|telegram|discord)\\/webhook$/.test(pathname) ||
|
|
1068
1100
|
/^\\/channels\\/[^/]+\\/whatsapp\\/(?:zapster|meta)\\/webhook$/.test(pathname)
|
|
1069
1101
|
);
|
|
1070
1102
|
}
|
|
@@ -1103,71 +1135,6 @@ async function forwardHostedChannelWebhook(request, env, url) {
|
|
|
1103
1135
|
});
|
|
1104
1136
|
}
|
|
1105
1137
|
|
|
1106
|
-
async function handleTursoHealth(request, env) {
|
|
1107
|
-
const auth = authorizeAdmin(request, env);
|
|
1108
|
-
|
|
1109
|
-
if (auth) {
|
|
1110
|
-
return auth;
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
const configError = requireTurso(env);
|
|
1114
|
-
|
|
1115
|
-
if (configError) {
|
|
1116
|
-
return configError;
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
const response = await fetch(toTursoBaseUrl(env.TURSO_DATABASE_URL) + "/health", {
|
|
1120
|
-
headers: {
|
|
1121
|
-
Authorization: \`Bearer \${env.TURSO_AUTH_TOKEN}\`,
|
|
1122
|
-
},
|
|
1123
|
-
});
|
|
1124
|
-
|
|
1125
|
-
return Response.json({
|
|
1126
|
-
driver: "turso",
|
|
1127
|
-
ok: response.ok,
|
|
1128
|
-
status: response.status,
|
|
1129
|
-
}, { status: response.ok ? 200 : 502 });
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
async function handleTursoQuery(request, env) {
|
|
1133
|
-
const auth = authorizeAdmin(request, env);
|
|
1134
|
-
|
|
1135
|
-
if (auth) {
|
|
1136
|
-
return auth;
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
const configError = requireTurso(env);
|
|
1140
|
-
|
|
1141
|
-
if (configError) {
|
|
1142
|
-
return configError;
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
let body;
|
|
1146
|
-
|
|
1147
|
-
try {
|
|
1148
|
-
body = await request.json();
|
|
1149
|
-
} catch {
|
|
1150
|
-
return Response.json(
|
|
1151
|
-
{ error: { code: "validation_error", message: "Expected JSON body with sql and optional args fields." } },
|
|
1152
|
-
{ status: 400 },
|
|
1153
|
-
);
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
const sql = String(body.sql || "").trim();
|
|
1157
|
-
|
|
1158
|
-
if (!sql) {
|
|
1159
|
-
return Response.json({ error: { code: "validation_error", message: "sql must be non-empty." } }, { status: 400 });
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
const args = Array.isArray(body.args) ? body.args : [];
|
|
1163
|
-
try {
|
|
1164
|
-
const result = await executeTursoSql(env, sql, args);
|
|
1165
|
-
return Response.json(result);
|
|
1166
|
-
} catch (error) {
|
|
1167
|
-
return hostedErrorResponse(error);
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
1138
|
async function handleFile(request, env, rawKey) {
|
|
1172
1139
|
const auth = authorizeAdmin(request, env);
|
|
1173
1140
|
|
|
@@ -1295,6 +1262,7 @@ async function handleTool(request, env, toolName) {
|
|
|
1295
1262
|
},
|
|
1296
1263
|
input: result.input,
|
|
1297
1264
|
output: result.output,
|
|
1265
|
+
...(result.rendered ? { rendered: result.rendered } : {}),
|
|
1298
1266
|
});
|
|
1299
1267
|
} catch (error) {
|
|
1300
1268
|
return hostedErrorResponse(error);
|
|
@@ -1340,35 +1308,12 @@ async function handleChat(request, env) {
|
|
|
1340
1308
|
let content;
|
|
1341
1309
|
const toolCalls = [];
|
|
1342
1310
|
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
input: toolRequest.input,
|
|
1350
|
-
env,
|
|
1351
|
-
signal: request.signal,
|
|
1352
|
-
invocation: "chat",
|
|
1353
|
-
});
|
|
1354
|
-
toolCalls.push(toolResult);
|
|
1355
|
-
content =
|
|
1356
|
-
toolResult.visibility === "internal"
|
|
1357
|
-
? \`Tool \${toolResult.name}: completed\`
|
|
1358
|
-
: \`Tool \${toolResult.name}: \${JSON.stringify(toolResult.output)}\`;
|
|
1359
|
-
} catch (error) {
|
|
1360
|
-
await persistFailure(env, conversationId, message, error);
|
|
1361
|
-
return hostedErrorResponse(error);
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
if (content === undefined) {
|
|
1366
|
-
try {
|
|
1367
|
-
content = await callHostedProvider(env, [...previousMessages, { role: "user", content: message }], request.signal);
|
|
1368
|
-
} catch (error) {
|
|
1369
|
-
await persistFailure(env, conversationId, message, error);
|
|
1370
|
-
return hostedErrorResponse(error);
|
|
1371
|
-
}
|
|
1311
|
+
try {
|
|
1312
|
+
const providerResult = await callHostedProvider(env, [...previousMessages, { role: "user", content: message }], request.signal, toolCalls);
|
|
1313
|
+
content = providerResult.content;
|
|
1314
|
+
} catch (error) {
|
|
1315
|
+
await persistFailure(env, conversationId, message, error, toolCalls);
|
|
1316
|
+
return hostedErrorResponse(error);
|
|
1372
1317
|
}
|
|
1373
1318
|
|
|
1374
1319
|
const persisted = await persist(env, {
|
|
@@ -1388,7 +1333,7 @@ async function handleChat(request, env) {
|
|
|
1388
1333
|
}
|
|
1389
1334
|
|
|
1390
1335
|
async function handleConversationRead(request, env, action, conversationId) {
|
|
1391
|
-
const auth = await
|
|
1336
|
+
const auth = await authorizeConversationRead(request, env);
|
|
1392
1337
|
|
|
1393
1338
|
if (auth) {
|
|
1394
1339
|
return auth;
|
|
@@ -1436,7 +1381,7 @@ function isRecord(value) {
|
|
|
1436
1381
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1437
1382
|
}
|
|
1438
1383
|
|
|
1439
|
-
async function callHostedProvider(env, messages, signal) {
|
|
1384
|
+
async function callHostedProvider(env, messages, signal, toolCalls = []) {
|
|
1440
1385
|
const adapter = getProviderAdapter(manifest.provider);
|
|
1441
1386
|
const hostedTools = createHostedTools(env);
|
|
1442
1387
|
const clock = buildRuntimeClockContext({
|
|
@@ -1457,12 +1402,14 @@ async function callHostedProvider(env, messages, signal) {
|
|
|
1457
1402
|
),
|
|
1458
1403
|
messages,
|
|
1459
1404
|
tools: hostedTools,
|
|
1460
|
-
toolRuntime: createHostedProviderToolRuntime(env, signal, clock),
|
|
1405
|
+
toolRuntime: createHostedProviderToolRuntime(env, signal, clock, toolCalls),
|
|
1461
1406
|
env,
|
|
1462
1407
|
signal,
|
|
1463
1408
|
});
|
|
1464
1409
|
|
|
1465
|
-
return
|
|
1410
|
+
return {
|
|
1411
|
+
content: result.message.content,
|
|
1412
|
+
};
|
|
1466
1413
|
}
|
|
1467
1414
|
|
|
1468
1415
|
function appendHostedKnowledgePromptPolicy(baseInstructions) {
|
|
@@ -1888,36 +1835,17 @@ async function hostedFakeEmbedding(input, dimensions) {
|
|
|
1888
1835
|
return norm === 0 ? values : values.map((value) => Number((value / norm).toFixed(8)));
|
|
1889
1836
|
}
|
|
1890
1837
|
|
|
1891
|
-
async function persistFailure(env, conversationId, userMessage, error) {
|
|
1838
|
+
async function persistFailure(env, conversationId, userMessage, error, toolCalls = []) {
|
|
1892
1839
|
await persist(env, {
|
|
1893
1840
|
conversationId,
|
|
1894
1841
|
userMessage,
|
|
1895
1842
|
status: "failed",
|
|
1896
1843
|
errorCode: error && typeof error === "object" && "code" in error ? String(error.code) : "runtime_error",
|
|
1897
1844
|
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1898
|
-
toolCalls
|
|
1845
|
+
toolCalls,
|
|
1899
1846
|
}).catch(() => undefined);
|
|
1900
1847
|
}
|
|
1901
1848
|
|
|
1902
|
-
function parseToolRequest(content) {
|
|
1903
|
-
let parsed;
|
|
1904
|
-
|
|
1905
|
-
try {
|
|
1906
|
-
parsed = JSON.parse(content);
|
|
1907
|
-
} catch {
|
|
1908
|
-
return null;
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
if (!isRecord(parsed) || typeof parsed.tool !== "string" || parsed.tool.length === 0) {
|
|
1912
|
-
return null;
|
|
1913
|
-
}
|
|
1914
|
-
|
|
1915
|
-
return {
|
|
1916
|
-
name: parsed.tool,
|
|
1917
|
-
input: "input" in parsed ? parsed.input : {},
|
|
1918
|
-
};
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
1849
|
function inspectHostedDatabase() {
|
|
1922
1850
|
const schema = manifest.storage.database.driver === "turso" ? manifest.storage.database.schema : null;
|
|
1923
1851
|
|
|
@@ -1971,21 +1899,28 @@ function hostedIntegrations(env) {
|
|
|
1971
1899
|
);
|
|
1972
1900
|
}
|
|
1973
1901
|
|
|
1974
|
-
function createHostedProviderToolRuntime(env, signal, clock) {
|
|
1902
|
+
function createHostedProviderToolRuntime(env, signal, clock, toolCalls) {
|
|
1975
1903
|
const hostedTools = createHostedTools(env);
|
|
1976
1904
|
|
|
1977
1905
|
return {
|
|
1978
1906
|
definitions: hostedTools,
|
|
1979
|
-
execute(request) {
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1907
|
+
async execute(request) {
|
|
1908
|
+
try {
|
|
1909
|
+
const result = await executeHostedTool({
|
|
1910
|
+
tools: hostedTools,
|
|
1911
|
+
name: request.name,
|
|
1912
|
+
input: request.input,
|
|
1913
|
+
env,
|
|
1914
|
+
signal,
|
|
1915
|
+
invocation: "chat",
|
|
1916
|
+
clock,
|
|
1917
|
+
});
|
|
1918
|
+
toolCalls?.push(result);
|
|
1919
|
+
return result;
|
|
1920
|
+
} catch (error) {
|
|
1921
|
+
toolCalls?.push(failedHostedToolCall(hostedTools, request, error));
|
|
1922
|
+
throw error;
|
|
1923
|
+
}
|
|
1989
1924
|
},
|
|
1990
1925
|
};
|
|
1991
1926
|
}
|
|
@@ -2008,6 +1943,12 @@ async function executeHostedTool(request) {
|
|
|
2008
1943
|
timeZone: manifest.timeZone,
|
|
2009
1944
|
env: request.env,
|
|
2010
1945
|
});
|
|
1946
|
+
const runtime = {
|
|
1947
|
+
environment: "hosted",
|
|
1948
|
+
invocation: request.invocation ?? "tool",
|
|
1949
|
+
target: "cloudflare",
|
|
1950
|
+
database: manifest.storage.database.driver === "turso" ? "turso" : "none",
|
|
1951
|
+
};
|
|
2011
1952
|
const output = await runToolWithTimeout(
|
|
2012
1953
|
tool,
|
|
2013
1954
|
input,
|
|
@@ -2016,12 +1957,7 @@ async function executeHostedTool(request) {
|
|
|
2016
1957
|
database,
|
|
2017
1958
|
signal: request.signal,
|
|
2018
1959
|
clock,
|
|
2019
|
-
runtime
|
|
2020
|
-
environment: "hosted",
|
|
2021
|
-
invocation: request.invocation ?? "tool",
|
|
2022
|
-
target: "cloudflare",
|
|
2023
|
-
database: manifest.storage.database.driver === "turso" ? "turso" : "none",
|
|
2024
|
-
},
|
|
1960
|
+
runtime,
|
|
2025
1961
|
},
|
|
2026
1962
|
tool.timeoutMs ?? DEFAULT_TOOL_TIMEOUT_MS,
|
|
2027
1963
|
);
|
|
@@ -2030,6 +1966,8 @@ async function executeHostedTool(request) {
|
|
|
2030
1966
|
validateSchema(output, tool.outputSchema, \`tool "\${tool.name}" output\`);
|
|
2031
1967
|
}
|
|
2032
1968
|
|
|
1969
|
+
const rendered = renderHostedToolOutput(tool, input, output, runtime, clock);
|
|
1970
|
+
|
|
2033
1971
|
return {
|
|
2034
1972
|
id,
|
|
2035
1973
|
name: tool.name,
|
|
@@ -2037,9 +1975,135 @@ async function executeHostedTool(request) {
|
|
|
2037
1975
|
status: "completed",
|
|
2038
1976
|
input,
|
|
2039
1977
|
output,
|
|
1978
|
+
...(rendered ? { rendered } : {}),
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
function failedHostedToolCall(tools, request, error) {
|
|
1983
|
+
const tool = tools.find((candidate) => candidate.name === request.name);
|
|
1984
|
+
|
|
1985
|
+
return {
|
|
1986
|
+
id: crypto.randomUUID(),
|
|
1987
|
+
name: String(request.name || ""),
|
|
1988
|
+
visibility: tool?.visibility ?? "user",
|
|
1989
|
+
status: "failed",
|
|
1990
|
+
input: request.input ?? {},
|
|
1991
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
function renderHostedToolOutput(tool, input, output, runtime, clock) {
|
|
1996
|
+
if (!tool.render) {
|
|
1997
|
+
return undefined;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
const rendered = tool.render(output, {
|
|
2001
|
+
input,
|
|
2002
|
+
runtime,
|
|
2003
|
+
clock,
|
|
2004
|
+
});
|
|
2005
|
+
|
|
2006
|
+
if (typeof rendered === "string") {
|
|
2007
|
+
return { text: rendered };
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
if (!isRecord(rendered) || typeof rendered.text !== "string" || rendered.text.trim().length === 0) {
|
|
2011
|
+
throw agentKitError("tool_validation_error", \`tool "\${tool.name}" render must return a non-empty text string.\`);
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
if (rendered.blocks !== undefined) {
|
|
2015
|
+
if (!Array.isArray(rendered.blocks)) {
|
|
2016
|
+
throw agentKitError("tool_validation_error", \`tool "\${tool.name}" render.blocks must be an array when provided.\`);
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
for (const [index, block] of rendered.blocks.entries()) {
|
|
2020
|
+
validateRenderBlock(block, \`tool "\${tool.name}" render.blocks[\${index}]\`);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
return {
|
|
2025
|
+
text: rendered.text,
|
|
2026
|
+
...(rendered.blocks ? { blocks: rendered.blocks } : {}),
|
|
2040
2027
|
};
|
|
2041
2028
|
}
|
|
2042
2029
|
|
|
2030
|
+
function validateRenderBlock(block, label) {
|
|
2031
|
+
if (!isRecord(block)) {
|
|
2032
|
+
throw agentKitError("tool_validation_error", \`\${label} must be an object.\`);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
if (block.type === "text") {
|
|
2036
|
+
if (typeof block.text !== "string" || block.text.trim().length === 0) {
|
|
2037
|
+
throw agentKitError("tool_validation_error", \`\${label}.text must be a non-empty string.\`);
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
return;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
if (block.type === "card") {
|
|
2044
|
+
if (typeof block.title !== "string" || block.title.trim().length === 0) {
|
|
2045
|
+
throw agentKitError("tool_validation_error", \`\${label}.title must be a non-empty string.\`);
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
validateOptionalString(block.subtitle, \`\${label}.subtitle\`);
|
|
2049
|
+
validateRenderFields(block.fields, \`\${label}.fields\`);
|
|
2050
|
+
validateRenderActions(block.actions, \`\${label}.actions\`);
|
|
2051
|
+
return;
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
throw agentKitError("tool_validation_error", \`\${label}.type must be "text" or "card".\`);
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
function validateRenderFields(value, label) {
|
|
2058
|
+
if (value === undefined) {
|
|
2059
|
+
return;
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
if (!Array.isArray(value)) {
|
|
2063
|
+
throw agentKitError("tool_validation_error", \`\${label} must be an array when provided.\`);
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
for (const [index, field] of value.entries()) {
|
|
2067
|
+
if (!isRecord(field)) {
|
|
2068
|
+
throw agentKitError("tool_validation_error", \`\${label}[\${index}] must be an object.\`);
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
validateRequiredString(field.label, \`\${label}[\${index}].label\`);
|
|
2072
|
+
validateRequiredString(field.value, \`\${label}[\${index}].value\`);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
function validateRenderActions(value, label) {
|
|
2077
|
+
if (value === undefined) {
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
if (!Array.isArray(value)) {
|
|
2082
|
+
throw agentKitError("tool_validation_error", \`\${label} must be an array when provided.\`);
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
for (const [index, action] of value.entries()) {
|
|
2086
|
+
if (!isRecord(action)) {
|
|
2087
|
+
throw agentKitError("tool_validation_error", \`\${label}[\${index}] must be an object.\`);
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
validateRequiredString(action.label, \`\${label}[\${index}].label\`);
|
|
2091
|
+
validateOptionalString(action.href, \`\${label}[\${index}].href\`);
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
function validateRequiredString(value, label) {
|
|
2096
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
2097
|
+
throw agentKitError("tool_validation_error", \`\${label} must be a non-empty string.\`);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
function validateOptionalString(value, label) {
|
|
2102
|
+
if (value !== undefined && typeof value !== "string") {
|
|
2103
|
+
throw agentKitError("tool_validation_error", \`\${label} must be a string when provided.\`);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2043
2107
|
function resolveToolSecrets(tool, env) {
|
|
2044
2108
|
const secrets = {};
|
|
2045
2109
|
|
|
@@ -2306,6 +2370,20 @@ function allowsNull(schema) {
|
|
|
2306
2370
|
}
|
|
2307
2371
|
|
|
2308
2372
|
async function authorizeChat(request, env, body) {
|
|
2373
|
+
return authorizeDeployAccess(request, env, body, {
|
|
2374
|
+
notConfiguredCode: "chat_access_not_configured",
|
|
2375
|
+
notConfiguredMessage: "Hosted chat requires a deploy access token gate.",
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
async function authorizeConversationRead(request, env) {
|
|
2380
|
+
return authorizeDeployAccess(request, env, {}, {
|
|
2381
|
+
notConfiguredCode: "conversation_access_not_configured",
|
|
2382
|
+
notConfiguredMessage: "Hosted conversation reads require a deploy access token gate.",
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
async function authorizeDeployAccess(request, env, body, options) {
|
|
2309
2387
|
const runtimeGate = await authorizeRuntimeGate(request, env, body);
|
|
2310
2388
|
|
|
2311
2389
|
if (runtimeGate) {
|
|
@@ -2316,52 +2394,28 @@ async function authorizeChat(request, env, body) {
|
|
|
2316
2394
|
return runtimeGate;
|
|
2317
2395
|
}
|
|
2318
2396
|
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2397
|
+
const token = deployAccessToken(request, body);
|
|
2398
|
+
const acceptedTokens = [env.AGENTKIT_PRIVATE_TOKEN, env.AGENTKIT_ACCESS_TOKEN].filter(
|
|
2399
|
+
(value) => typeof value === "string" && value.length > 0,
|
|
2400
|
+
);
|
|
2322
2401
|
|
|
2323
|
-
if (
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
{
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
message: "Private deploy requires AGENTKIT_PRIVATE_TOKEN to be set as a Cloudflare secret.",
|
|
2330
|
-
},
|
|
2402
|
+
if (acceptedTokens.length === 0) {
|
|
2403
|
+
return Response.json(
|
|
2404
|
+
{
|
|
2405
|
+
error: {
|
|
2406
|
+
code: options.notConfiguredCode,
|
|
2407
|
+
message: options.notConfiguredMessage,
|
|
2331
2408
|
},
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
const expected = \`Bearer \${env.AGENTKIT_PRIVATE_TOKEN}\`;
|
|
2337
|
-
if (request.headers.get("authorization") !== expected) {
|
|
2338
|
-
return Response.json(
|
|
2339
|
-
{ error: { code: "unauthorized", message: "Missing or invalid deploy access token." } },
|
|
2340
|
-
{ status: 401 },
|
|
2341
|
-
);
|
|
2342
|
-
}
|
|
2409
|
+
},
|
|
2410
|
+
{ status: 503 },
|
|
2411
|
+
);
|
|
2343
2412
|
}
|
|
2344
2413
|
|
|
2345
|
-
if (
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
code: "deploy_not_ready",
|
|
2351
|
-
message: "Token deploy requires AGENTKIT_ACCESS_TOKEN to be set as a Cloudflare secret.",
|
|
2352
|
-
},
|
|
2353
|
-
},
|
|
2354
|
-
{ status: 503 },
|
|
2355
|
-
);
|
|
2356
|
-
}
|
|
2357
|
-
|
|
2358
|
-
const expected = \`Bearer \${env.AGENTKIT_ACCESS_TOKEN}\`;
|
|
2359
|
-
if (request.headers.get("authorization") !== expected) {
|
|
2360
|
-
return Response.json(
|
|
2361
|
-
{ error: { code: "unauthorized", message: "Missing or invalid deploy access token." } },
|
|
2362
|
-
{ status: 401 },
|
|
2363
|
-
);
|
|
2364
|
-
}
|
|
2414
|
+
if (!token || !acceptedTokens.includes(token)) {
|
|
2415
|
+
return Response.json(
|
|
2416
|
+
{ error: { code: "unauthorized", message: "Missing or invalid deploy access token." } },
|
|
2417
|
+
{ status: 401 },
|
|
2418
|
+
);
|
|
2365
2419
|
}
|
|
2366
2420
|
|
|
2367
2421
|
return null;
|
|
@@ -2903,6 +2957,7 @@ CREATE TABLE IF NOT EXISTS tool_calls (
|
|
|
2903
2957
|
status TEXT NOT NULL,
|
|
2904
2958
|
input_json TEXT NOT NULL,
|
|
2905
2959
|
output_json TEXT,
|
|
2960
|
+
rendered_json TEXT,
|
|
2906
2961
|
error_message TEXT,
|
|
2907
2962
|
created_at TEXT NOT NULL,
|
|
2908
2963
|
completed_at TEXT
|
|
@@ -118,7 +118,7 @@ function renderCompose(agentName: string): string {
|
|
|
118
118
|
- agentkit_data:/data
|
|
119
119
|
- agentkit_files:/capsule/.agentkit/files
|
|
120
120
|
healthcheck:
|
|
121
|
-
test: ["CMD", "
|
|
121
|
+
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:4123/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
|
122
122
|
interval: 30s
|
|
123
123
|
timeout: 5s
|
|
124
124
|
retries: 3
|
package/src/storage/sqlite.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { DatabaseArgs, DatabaseResult, DatabaseRow, DatabaseStatement } fro
|
|
|
6
6
|
import type { AgentMessageRole, ProviderRunResult } from "../providers";
|
|
7
7
|
import type { LoadedAgentCapsule } from "../runtime/config";
|
|
8
8
|
import { AgentKitError } from "../runtime/errors";
|
|
9
|
-
import { KNOWLEDGE_MIGRATION_ID, KNOWLEDGE_SCHEMA_SQL } from "../runtime/knowledge/schema";
|
|
9
|
+
import { applyKnowledgeSchema, KNOWLEDGE_MIGRATION_ID, KNOWLEDGE_SCHEMA_SQL } from "../runtime/knowledge/schema";
|
|
10
10
|
|
|
11
11
|
export type ConversationSummary = {
|
|
12
12
|
id: string;
|
|
@@ -806,7 +806,12 @@ export class SqliteAgentKitStore {
|
|
|
806
806
|
continue;
|
|
807
807
|
}
|
|
808
808
|
|
|
809
|
-
|
|
809
|
+
if (migration.id === KNOWLEDGE_MIGRATION_ID) {
|
|
810
|
+
applyKnowledgeSchema(this.db);
|
|
811
|
+
} else {
|
|
812
|
+
this.db.exec(migration.sql);
|
|
813
|
+
}
|
|
814
|
+
|
|
810
815
|
this.db
|
|
811
816
|
.prepare("INSERT INTO agentkit_migrations (id, applied_at) VALUES ($id, $appliedAt)")
|
|
812
817
|
.run({ $id: migration.id, $appliedAt: new Date().toISOString() });
|