@andreprado/agentkit 0.1.0-alpha.17 → 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 +14 -8
- package/docs/guides/add-knowledge.md +10 -0
- package/docs/guides/add-managed-composio.md +43 -17
- package/docs/guides/channel-security.md +60 -39
- package/docs/guides/connect-discord.md +178 -0
- package/docs/guides/create-agent.md +13 -0
- package/docs/guides/debug-channel.md +147 -0
- package/docs/guides/improve-from-production.md +151 -0
- package/docs/guides/prepare-deploy.md +30 -14
- 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 +106 -15
- package/docs/llms.txt +22 -4
- package/package.json +1 -3
- package/src/cli/args.ts +23 -2
- package/src/cli/cloud-client.ts +75 -0
- package/src/cli/commands/channels.ts +139 -14
- package/src/cli/deploy-chat-ui.ts +146 -3
- package/src/cli/deploy-readiness.ts +57 -1
- package/src/cli/help.ts +32 -8
- package/src/cli/index.ts +447 -17
- package/src/create-project.ts +13 -2
- package/src/index.ts +46 -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 +39 -3
- package/src/runtime/core/manifest.ts +2 -0
- 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/inspect.ts +1 -0
- package/src/runtime/integrations/composio.ts +168 -2
- 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 +479 -194
- 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 +12 -2
- 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
- package/docs/guides/agentkit-skills-architecture.md +0 -472
- package/docs/guides/channels-implementation-map.md +0 -243
- package/docs/guides/channels-production-handoff.md +0 -118
- package/docs/portable-deploy-release-checklist.md +0 -41
|
@@ -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) {
|
|
@@ -731,6 +751,22 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
731
751
|
return this.getMessages(url.searchParams.get("conversationId"));
|
|
732
752
|
}
|
|
733
753
|
|
|
754
|
+
if (request.method === "GET" && url.pathname === "/conversations") {
|
|
755
|
+
return this.listConversations();
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const conversationTraceMatch = url.pathname.match(/^\\/conversations\\/([^/]+)\\/trace$/);
|
|
759
|
+
|
|
760
|
+
if (request.method === "GET" && conversationTraceMatch) {
|
|
761
|
+
return this.getConversationTrace(decodeURIComponent(conversationTraceMatch[1] || ""));
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
const conversationMatch = url.pathname.match(/^\\/conversations\\/([^/]+)$/);
|
|
765
|
+
|
|
766
|
+
if (request.method === "GET" && conversationMatch) {
|
|
767
|
+
return this.getConversation(decodeURIComponent(conversationMatch[1] || ""));
|
|
768
|
+
}
|
|
769
|
+
|
|
734
770
|
return Response.json({ error: { code: "not_found", message: "Unknown Durable Object route." } }, { status: 404 });
|
|
735
771
|
}
|
|
736
772
|
|
|
@@ -754,6 +790,129 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
754
790
|
});
|
|
755
791
|
}
|
|
756
792
|
|
|
793
|
+
listConversations() {
|
|
794
|
+
const rows = this.sql.exec(\`
|
|
795
|
+
SELECT conversations.id, conversations.agent_name, conversations.title, conversations.created_at, conversations.updated_at, COUNT(messages.id) AS message_count
|
|
796
|
+
FROM conversations
|
|
797
|
+
LEFT JOIN messages ON messages.conversation_id = conversations.id
|
|
798
|
+
GROUP BY conversations.id, conversations.agent_name, conversations.title, conversations.created_at, conversations.updated_at
|
|
799
|
+
ORDER BY conversations.updated_at DESC
|
|
800
|
+
\`).toArray();
|
|
801
|
+
|
|
802
|
+
return Response.json({
|
|
803
|
+
conversations: rows.map((row) => ({
|
|
804
|
+
id: String(row.id),
|
|
805
|
+
agentName: String(row.agent_name),
|
|
806
|
+
title: row.title === null || row.title === undefined ? null : String(row.title),
|
|
807
|
+
createdAt: String(row.created_at),
|
|
808
|
+
updatedAt: String(row.updated_at),
|
|
809
|
+
messageCount: Number(row.message_count || 0),
|
|
810
|
+
})),
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
getConversation(conversationId) {
|
|
815
|
+
const conversation = this.readConversation(conversationId);
|
|
816
|
+
|
|
817
|
+
if (!conversation) {
|
|
818
|
+
return Response.json(
|
|
819
|
+
{ error: { code: "conversation_not_found", message: \`Conversation "\${conversationId}" was not found.\` } },
|
|
820
|
+
{ status: 404 },
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
return Response.json(conversation);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
getConversationTrace(conversationId) {
|
|
828
|
+
const conversation = this.readConversation(conversationId);
|
|
829
|
+
|
|
830
|
+
if (!conversation) {
|
|
831
|
+
return Response.json(
|
|
832
|
+
{ error: { code: "conversation_not_found", message: \`Conversation "\${conversationId}" was not found.\` } },
|
|
833
|
+
{ status: 404 },
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const runs = this.sql.exec(
|
|
838
|
+
"SELECT id, conversation_id, provider, model, status, error_code, error_message, created_at, completed_at FROM runs WHERE conversation_id = ? ORDER BY rowid ASC",
|
|
839
|
+
conversationId,
|
|
840
|
+
).toArray();
|
|
841
|
+
|
|
842
|
+
return Response.json({
|
|
843
|
+
...conversation,
|
|
844
|
+
runs: runs.map((run) => ({
|
|
845
|
+
id: String(run.id),
|
|
846
|
+
conversationId: String(run.conversation_id),
|
|
847
|
+
provider: String(run.provider),
|
|
848
|
+
model: String(run.model),
|
|
849
|
+
status: String(run.status),
|
|
850
|
+
errorCode: run.error_code === null || run.error_code === undefined ? null : String(run.error_code),
|
|
851
|
+
errorMessage: run.error_message === null || run.error_message === undefined ? null : String(run.error_message),
|
|
852
|
+
startedAt: String(run.created_at),
|
|
853
|
+
completedAt: run.completed_at === null || run.completed_at === undefined ? null : String(run.completed_at),
|
|
854
|
+
toolCalls: this.readToolCalls(String(run.id)),
|
|
855
|
+
})),
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
readConversation(conversationId) {
|
|
860
|
+
if (!conversationId) {
|
|
861
|
+
return null;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const row = this.sql.exec(
|
|
865
|
+
"SELECT id, agent_name, title, created_at, updated_at FROM conversations WHERE id = ?",
|
|
866
|
+
conversationId,
|
|
867
|
+
).one();
|
|
868
|
+
|
|
869
|
+
if (!row) {
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const messages = this.sql.exec(
|
|
874
|
+
"SELECT id, conversation_id, role, content, created_at FROM messages WHERE conversation_id = ? ORDER BY rowid ASC",
|
|
875
|
+
conversationId,
|
|
876
|
+
).toArray();
|
|
877
|
+
|
|
878
|
+
return {
|
|
879
|
+
id: String(row.id),
|
|
880
|
+
agentName: String(row.agent_name),
|
|
881
|
+
title: row.title === null || row.title === undefined ? null : String(row.title),
|
|
882
|
+
createdAt: String(row.created_at),
|
|
883
|
+
updatedAt: String(row.updated_at),
|
|
884
|
+
messages: messages.map((message) => ({
|
|
885
|
+
id: String(message.id),
|
|
886
|
+
conversationId: String(message.conversation_id),
|
|
887
|
+
role: String(message.role),
|
|
888
|
+
content: String(message.content),
|
|
889
|
+
createdAt: String(message.created_at),
|
|
890
|
+
})),
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
readToolCalls(runId) {
|
|
895
|
+
const rows = this.sql.exec(
|
|
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",
|
|
897
|
+
runId,
|
|
898
|
+
).toArray();
|
|
899
|
+
|
|
900
|
+
return rows.map((row) => ({
|
|
901
|
+
id: String(row.id),
|
|
902
|
+
runId: String(row.run_id),
|
|
903
|
+
conversationId: String(row.conversation_id),
|
|
904
|
+
name: String(row.tool_name),
|
|
905
|
+
visibility: String(row.visibility),
|
|
906
|
+
status: String(row.status),
|
|
907
|
+
input: parseStoredJson(row.input_json, {}),
|
|
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),
|
|
910
|
+
errorMessage: row.error_message === null || row.error_message === undefined ? null : String(row.error_message),
|
|
911
|
+
createdAt: String(row.created_at),
|
|
912
|
+
completedAt: row.completed_at === null || row.completed_at === undefined ? null : String(row.completed_at),
|
|
913
|
+
}));
|
|
914
|
+
}
|
|
915
|
+
|
|
757
916
|
persistMessages(input) {
|
|
758
917
|
const now = new Date().toISOString();
|
|
759
918
|
const conversationId = String(input.conversationId || crypto.randomUUID());
|
|
@@ -805,7 +964,7 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
805
964
|
|
|
806
965
|
for (const toolCall of input.toolCalls || []) {
|
|
807
966
|
this.sql.exec(
|
|
808
|
-
"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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
809
968
|
String(toolCall.id || crypto.randomUUID()),
|
|
810
969
|
runId,
|
|
811
970
|
conversationId,
|
|
@@ -814,6 +973,7 @@ export class AgentKitConversationStore extends DurableObject {
|
|
|
814
973
|
String(toolCall.status || "completed"),
|
|
815
974
|
JSON.stringify(toolCall.input ?? {}),
|
|
816
975
|
toolCall.output === undefined ? null : JSON.stringify(toolCall.output),
|
|
976
|
+
toolCall.rendered === undefined ? null : JSON.stringify(toolCall.rendered),
|
|
817
977
|
toolCall.errorMessage ? String(toolCall.errorMessage) : null,
|
|
818
978
|
now,
|
|
819
979
|
now,
|
|
@@ -867,6 +1027,15 @@ export default {
|
|
|
867
1027
|
}
|
|
868
1028
|
|
|
869
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
|
+
|
|
870
1039
|
return Response.json({
|
|
871
1040
|
agent: manifest.name,
|
|
872
1041
|
status: "ready",
|
|
@@ -876,7 +1045,16 @@ export default {
|
|
|
876
1045
|
}
|
|
877
1046
|
|
|
878
1047
|
if (request.method === "GET" && url.pathname === "/health") {
|
|
879
|
-
|
|
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 });
|
|
880
1058
|
}
|
|
881
1059
|
|
|
882
1060
|
if (isHostedChannelWebhookPath(url.pathname)) {
|
|
@@ -887,16 +1065,24 @@ export default {
|
|
|
887
1065
|
return handleChat(request, env);
|
|
888
1066
|
}
|
|
889
1067
|
|
|
890
|
-
if (request.method === "
|
|
891
|
-
return
|
|
1068
|
+
if (request.method === "GET" && (url.pathname === "/conversations" || url.pathname === "/v1/conversations")) {
|
|
1069
|
+
return handleConversationRead(request, env, "list");
|
|
892
1070
|
}
|
|
893
1071
|
|
|
894
|
-
|
|
895
|
-
|
|
1072
|
+
const conversationTraceMatch = url.pathname.match(/^\\/(?:v1\\/)?conversations\\/([^/]+)\\/trace$/);
|
|
1073
|
+
|
|
1074
|
+
if (request.method === "GET" && conversationTraceMatch) {
|
|
1075
|
+
return handleConversationRead(request, env, "trace", decodeURIComponent(conversationTraceMatch[1] || ""));
|
|
896
1076
|
}
|
|
897
1077
|
|
|
898
|
-
|
|
899
|
-
|
|
1078
|
+
const conversationMatch = url.pathname.match(/^\\/(?:v1\\/)?conversations\\/([^/]+)$/);
|
|
1079
|
+
|
|
1080
|
+
if (request.method === "GET" && conversationMatch) {
|
|
1081
|
+
return handleConversationRead(request, env, "show", decodeURIComponent(conversationMatch[1] || ""));
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
if (request.method === "POST" && url.pathname.startsWith("/tools/")) {
|
|
1085
|
+
return handleTool(request, env, decodeURIComponent(url.pathname.slice("/tools/".length)));
|
|
900
1086
|
}
|
|
901
1087
|
|
|
902
1088
|
if (url.pathname.startsWith("/files/")) {
|
|
@@ -909,8 +1095,8 @@ export default {
|
|
|
909
1095
|
|
|
910
1096
|
function isHostedChannelWebhookPath(pathname) {
|
|
911
1097
|
return (
|
|
912
|
-
/^\\/channels\\/[^/]+\\/(?:website\\/agentkit|telegram\\/telegram|whatsapp\\/(?:zapster|meta))\\/webhook$/.test(pathname) ||
|
|
913
|
-
/^\\/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) ||
|
|
914
1100
|
/^\\/channels\\/[^/]+\\/whatsapp\\/(?:zapster|meta)\\/webhook$/.test(pathname)
|
|
915
1101
|
);
|
|
916
1102
|
}
|
|
@@ -949,71 +1135,6 @@ async function forwardHostedChannelWebhook(request, env, url) {
|
|
|
949
1135
|
});
|
|
950
1136
|
}
|
|
951
1137
|
|
|
952
|
-
async function handleTursoHealth(request, env) {
|
|
953
|
-
const auth = authorizeAdmin(request, env);
|
|
954
|
-
|
|
955
|
-
if (auth) {
|
|
956
|
-
return auth;
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
const configError = requireTurso(env);
|
|
960
|
-
|
|
961
|
-
if (configError) {
|
|
962
|
-
return configError;
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
const response = await fetch(toTursoBaseUrl(env.TURSO_DATABASE_URL) + "/health", {
|
|
966
|
-
headers: {
|
|
967
|
-
Authorization: \`Bearer \${env.TURSO_AUTH_TOKEN}\`,
|
|
968
|
-
},
|
|
969
|
-
});
|
|
970
|
-
|
|
971
|
-
return Response.json({
|
|
972
|
-
driver: "turso",
|
|
973
|
-
ok: response.ok,
|
|
974
|
-
status: response.status,
|
|
975
|
-
}, { status: response.ok ? 200 : 502 });
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
async function handleTursoQuery(request, env) {
|
|
979
|
-
const auth = authorizeAdmin(request, env);
|
|
980
|
-
|
|
981
|
-
if (auth) {
|
|
982
|
-
return auth;
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
const configError = requireTurso(env);
|
|
986
|
-
|
|
987
|
-
if (configError) {
|
|
988
|
-
return configError;
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
let body;
|
|
992
|
-
|
|
993
|
-
try {
|
|
994
|
-
body = await request.json();
|
|
995
|
-
} catch {
|
|
996
|
-
return Response.json(
|
|
997
|
-
{ error: { code: "validation_error", message: "Expected JSON body with sql and optional args fields." } },
|
|
998
|
-
{ status: 400 },
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
const sql = String(body.sql || "").trim();
|
|
1003
|
-
|
|
1004
|
-
if (!sql) {
|
|
1005
|
-
return Response.json({ error: { code: "validation_error", message: "sql must be non-empty." } }, { status: 400 });
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
const args = Array.isArray(body.args) ? body.args : [];
|
|
1009
|
-
try {
|
|
1010
|
-
const result = await executeTursoSql(env, sql, args);
|
|
1011
|
-
return Response.json(result);
|
|
1012
|
-
} catch (error) {
|
|
1013
|
-
return hostedErrorResponse(error);
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
1138
|
async function handleFile(request, env, rawKey) {
|
|
1018
1139
|
const auth = authorizeAdmin(request, env);
|
|
1019
1140
|
|
|
@@ -1141,6 +1262,7 @@ async function handleTool(request, env, toolName) {
|
|
|
1141
1262
|
},
|
|
1142
1263
|
input: result.input,
|
|
1143
1264
|
output: result.output,
|
|
1265
|
+
...(result.rendered ? { rendered: result.rendered } : {}),
|
|
1144
1266
|
});
|
|
1145
1267
|
} catch (error) {
|
|
1146
1268
|
return hostedErrorResponse(error);
|
|
@@ -1186,35 +1308,12 @@ async function handleChat(request, env) {
|
|
|
1186
1308
|
let content;
|
|
1187
1309
|
const toolCalls = [];
|
|
1188
1310
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
input: toolRequest.input,
|
|
1196
|
-
env,
|
|
1197
|
-
signal: request.signal,
|
|
1198
|
-
invocation: "chat",
|
|
1199
|
-
});
|
|
1200
|
-
toolCalls.push(toolResult);
|
|
1201
|
-
content =
|
|
1202
|
-
toolResult.visibility === "internal"
|
|
1203
|
-
? \`Tool \${toolResult.name}: completed\`
|
|
1204
|
-
: \`Tool \${toolResult.name}: \${JSON.stringify(toolResult.output)}\`;
|
|
1205
|
-
} catch (error) {
|
|
1206
|
-
await persistFailure(env, conversationId, message, error);
|
|
1207
|
-
return hostedErrorResponse(error);
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
if (content === undefined) {
|
|
1212
|
-
try {
|
|
1213
|
-
content = await callHostedProvider(env, [...previousMessages, { role: "user", content: message }], request.signal);
|
|
1214
|
-
} catch (error) {
|
|
1215
|
-
await persistFailure(env, conversationId, message, error);
|
|
1216
|
-
return hostedErrorResponse(error);
|
|
1217
|
-
}
|
|
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);
|
|
1218
1317
|
}
|
|
1219
1318
|
|
|
1220
1319
|
const persisted = await persist(env, {
|
|
@@ -1233,6 +1332,39 @@ async function handleChat(request, env) {
|
|
|
1233
1332
|
});
|
|
1234
1333
|
}
|
|
1235
1334
|
|
|
1335
|
+
async function handleConversationRead(request, env, action, conversationId) {
|
|
1336
|
+
const auth = await authorizeConversationRead(request, env);
|
|
1337
|
+
|
|
1338
|
+
if (auth) {
|
|
1339
|
+
return auth;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
if (!env.AGENTKIT_CONVERSATIONS) {
|
|
1343
|
+
return Response.json({ error: { code: "conversations_not_configured", message: "Hosted conversation storage is not configured." } }, { status: 503 });
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
if (action === "list") {
|
|
1347
|
+
const stub = hostedConversationStore(env);
|
|
1348
|
+
return stub.fetch("https://agentkit.internal/conversations");
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
if (!conversationId) {
|
|
1352
|
+
return Response.json({ error: { code: "validation_error", message: "Missing conversation id." } }, { status: 400 });
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
const stub = hostedConversationStore(env);
|
|
1356
|
+
const suffix = action === "trace" ? "/trace" : "";
|
|
1357
|
+
const path = \`/conversations/\${encodeURIComponent(conversationId)}\${suffix}\`;
|
|
1358
|
+
const response = await stub.fetch(\`https://agentkit.internal\${path}\`);
|
|
1359
|
+
|
|
1360
|
+
if (response.status !== 404) {
|
|
1361
|
+
return response;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
const legacyStub = legacyConversationStore(env, conversationId);
|
|
1365
|
+
return legacyStub.fetch(\`https://agentkit.internal\${path}\`);
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1236
1368
|
function readChatMessage(body) {
|
|
1237
1369
|
if (typeof body.message === "string") {
|
|
1238
1370
|
return body.message.trim();
|
|
@@ -1249,7 +1381,7 @@ function isRecord(value) {
|
|
|
1249
1381
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1250
1382
|
}
|
|
1251
1383
|
|
|
1252
|
-
async function callHostedProvider(env, messages, signal) {
|
|
1384
|
+
async function callHostedProvider(env, messages, signal, toolCalls = []) {
|
|
1253
1385
|
const adapter = getProviderAdapter(manifest.provider);
|
|
1254
1386
|
const hostedTools = createHostedTools(env);
|
|
1255
1387
|
const clock = buildRuntimeClockContext({
|
|
@@ -1270,12 +1402,14 @@ async function callHostedProvider(env, messages, signal) {
|
|
|
1270
1402
|
),
|
|
1271
1403
|
messages,
|
|
1272
1404
|
tools: hostedTools,
|
|
1273
|
-
toolRuntime: createHostedProviderToolRuntime(env, signal, clock),
|
|
1405
|
+
toolRuntime: createHostedProviderToolRuntime(env, signal, clock, toolCalls),
|
|
1274
1406
|
env,
|
|
1275
1407
|
signal,
|
|
1276
1408
|
});
|
|
1277
1409
|
|
|
1278
|
-
return
|
|
1410
|
+
return {
|
|
1411
|
+
content: result.message.content,
|
|
1412
|
+
};
|
|
1279
1413
|
}
|
|
1280
1414
|
|
|
1281
1415
|
function appendHostedKnowledgePromptPolicy(baseInstructions) {
|
|
@@ -1701,36 +1835,17 @@ async function hostedFakeEmbedding(input, dimensions) {
|
|
|
1701
1835
|
return norm === 0 ? values : values.map((value) => Number((value / norm).toFixed(8)));
|
|
1702
1836
|
}
|
|
1703
1837
|
|
|
1704
|
-
async function persistFailure(env, conversationId, userMessage, error) {
|
|
1838
|
+
async function persistFailure(env, conversationId, userMessage, error, toolCalls = []) {
|
|
1705
1839
|
await persist(env, {
|
|
1706
1840
|
conversationId,
|
|
1707
1841
|
userMessage,
|
|
1708
1842
|
status: "failed",
|
|
1709
1843
|
errorCode: error && typeof error === "object" && "code" in error ? String(error.code) : "runtime_error",
|
|
1710
1844
|
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1711
|
-
toolCalls
|
|
1845
|
+
toolCalls,
|
|
1712
1846
|
}).catch(() => undefined);
|
|
1713
1847
|
}
|
|
1714
1848
|
|
|
1715
|
-
function parseToolRequest(content) {
|
|
1716
|
-
let parsed;
|
|
1717
|
-
|
|
1718
|
-
try {
|
|
1719
|
-
parsed = JSON.parse(content);
|
|
1720
|
-
} catch {
|
|
1721
|
-
return null;
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
if (!isRecord(parsed) || typeof parsed.tool !== "string" || parsed.tool.length === 0) {
|
|
1725
|
-
return null;
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
return {
|
|
1729
|
-
name: parsed.tool,
|
|
1730
|
-
input: "input" in parsed ? parsed.input : {},
|
|
1731
|
-
};
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
1849
|
function inspectHostedDatabase() {
|
|
1735
1850
|
const schema = manifest.storage.database.driver === "turso" ? manifest.storage.database.schema : null;
|
|
1736
1851
|
|
|
@@ -1784,21 +1899,28 @@ function hostedIntegrations(env) {
|
|
|
1784
1899
|
);
|
|
1785
1900
|
}
|
|
1786
1901
|
|
|
1787
|
-
function createHostedProviderToolRuntime(env, signal, clock) {
|
|
1902
|
+
function createHostedProviderToolRuntime(env, signal, clock, toolCalls) {
|
|
1788
1903
|
const hostedTools = createHostedTools(env);
|
|
1789
1904
|
|
|
1790
1905
|
return {
|
|
1791
1906
|
definitions: hostedTools,
|
|
1792
|
-
execute(request) {
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
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
|
+
}
|
|
1802
1924
|
},
|
|
1803
1925
|
};
|
|
1804
1926
|
}
|
|
@@ -1821,6 +1943,12 @@ async function executeHostedTool(request) {
|
|
|
1821
1943
|
timeZone: manifest.timeZone,
|
|
1822
1944
|
env: request.env,
|
|
1823
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
|
+
};
|
|
1824
1952
|
const output = await runToolWithTimeout(
|
|
1825
1953
|
tool,
|
|
1826
1954
|
input,
|
|
@@ -1829,12 +1957,7 @@ async function executeHostedTool(request) {
|
|
|
1829
1957
|
database,
|
|
1830
1958
|
signal: request.signal,
|
|
1831
1959
|
clock,
|
|
1832
|
-
runtime
|
|
1833
|
-
environment: "hosted",
|
|
1834
|
-
invocation: request.invocation ?? "tool",
|
|
1835
|
-
target: "cloudflare",
|
|
1836
|
-
database: manifest.storage.database.driver === "turso" ? "turso" : "none",
|
|
1837
|
-
},
|
|
1960
|
+
runtime,
|
|
1838
1961
|
},
|
|
1839
1962
|
tool.timeoutMs ?? DEFAULT_TOOL_TIMEOUT_MS,
|
|
1840
1963
|
);
|
|
@@ -1843,6 +1966,8 @@ async function executeHostedTool(request) {
|
|
|
1843
1966
|
validateSchema(output, tool.outputSchema, \`tool "\${tool.name}" output\`);
|
|
1844
1967
|
}
|
|
1845
1968
|
|
|
1969
|
+
const rendered = renderHostedToolOutput(tool, input, output, runtime, clock);
|
|
1970
|
+
|
|
1846
1971
|
return {
|
|
1847
1972
|
id,
|
|
1848
1973
|
name: tool.name,
|
|
@@ -1850,9 +1975,135 @@ async function executeHostedTool(request) {
|
|
|
1850
1975
|
status: "completed",
|
|
1851
1976
|
input,
|
|
1852
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 } : {}),
|
|
1853
2027
|
};
|
|
1854
2028
|
}
|
|
1855
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
|
+
|
|
1856
2107
|
function resolveToolSecrets(tool, env) {
|
|
1857
2108
|
const secrets = {};
|
|
1858
2109
|
|
|
@@ -2119,6 +2370,20 @@ function allowsNull(schema) {
|
|
|
2119
2370
|
}
|
|
2120
2371
|
|
|
2121
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) {
|
|
2122
2387
|
const runtimeGate = await authorizeRuntimeGate(request, env, body);
|
|
2123
2388
|
|
|
2124
2389
|
if (runtimeGate) {
|
|
@@ -2129,52 +2394,28 @@ async function authorizeChat(request, env, body) {
|
|
|
2129
2394
|
return runtimeGate;
|
|
2130
2395
|
}
|
|
2131
2396
|
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
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
|
+
);
|
|
2135
2401
|
|
|
2136
|
-
if (
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
{
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
message: "Private deploy requires AGENTKIT_PRIVATE_TOKEN to be set as a Cloudflare secret.",
|
|
2143
|
-
},
|
|
2402
|
+
if (acceptedTokens.length === 0) {
|
|
2403
|
+
return Response.json(
|
|
2404
|
+
{
|
|
2405
|
+
error: {
|
|
2406
|
+
code: options.notConfiguredCode,
|
|
2407
|
+
message: options.notConfiguredMessage,
|
|
2144
2408
|
},
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
const expected = \`Bearer \${env.AGENTKIT_PRIVATE_TOKEN}\`;
|
|
2150
|
-
if (request.headers.get("authorization") !== expected) {
|
|
2151
|
-
return Response.json(
|
|
2152
|
-
{ error: { code: "unauthorized", message: "Missing or invalid deploy access token." } },
|
|
2153
|
-
{ status: 401 },
|
|
2154
|
-
);
|
|
2155
|
-
}
|
|
2409
|
+
},
|
|
2410
|
+
{ status: 503 },
|
|
2411
|
+
);
|
|
2156
2412
|
}
|
|
2157
2413
|
|
|
2158
|
-
if (
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
code: "deploy_not_ready",
|
|
2164
|
-
message: "Token deploy requires AGENTKIT_ACCESS_TOKEN to be set as a Cloudflare secret.",
|
|
2165
|
-
},
|
|
2166
|
-
},
|
|
2167
|
-
{ status: 503 },
|
|
2168
|
-
);
|
|
2169
|
-
}
|
|
2170
|
-
|
|
2171
|
-
const expected = \`Bearer \${env.AGENTKIT_ACCESS_TOKEN}\`;
|
|
2172
|
-
if (request.headers.get("authorization") !== expected) {
|
|
2173
|
-
return Response.json(
|
|
2174
|
-
{ error: { code: "unauthorized", message: "Missing or invalid deploy access token." } },
|
|
2175
|
-
{ status: 401 },
|
|
2176
|
-
);
|
|
2177
|
-
}
|
|
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
|
+
);
|
|
2178
2419
|
}
|
|
2179
2420
|
|
|
2180
2421
|
return null;
|
|
@@ -2276,8 +2517,7 @@ async function persist(env, input) {
|
|
|
2276
2517
|
return {};
|
|
2277
2518
|
}
|
|
2278
2519
|
|
|
2279
|
-
const
|
|
2280
|
-
const stub = env.AGENTKIT_CONVERSATIONS.get(id);
|
|
2520
|
+
const stub = hostedConversationStore(env);
|
|
2281
2521
|
const response = await stub.fetch("https://agentkit.internal/messages", {
|
|
2282
2522
|
method: "POST",
|
|
2283
2523
|
body: JSON.stringify(input),
|
|
@@ -2295,8 +2535,7 @@ async function loadConversationMessages(env, conversationId) {
|
|
|
2295
2535
|
return [];
|
|
2296
2536
|
}
|
|
2297
2537
|
|
|
2298
|
-
const
|
|
2299
|
-
const stub = env.AGENTKIT_CONVERSATIONS.get(id);
|
|
2538
|
+
const stub = hostedConversationStore(env);
|
|
2300
2539
|
const response = await stub.fetch(
|
|
2301
2540
|
\`https://agentkit.internal/messages?conversationId=\${encodeURIComponent(conversationId)}\`,
|
|
2302
2541
|
);
|
|
@@ -2306,7 +2545,7 @@ async function loadConversationMessages(env, conversationId) {
|
|
|
2306
2545
|
}
|
|
2307
2546
|
|
|
2308
2547
|
const payload = await response.json();
|
|
2309
|
-
|
|
2548
|
+
const messages = Array.isArray(payload.messages)
|
|
2310
2549
|
? payload.messages.filter((message) =>
|
|
2311
2550
|
message &&
|
|
2312
2551
|
typeof message === "object" &&
|
|
@@ -2314,6 +2553,39 @@ async function loadConversationMessages(env, conversationId) {
|
|
|
2314
2553
|
typeof message.content === "string"
|
|
2315
2554
|
)
|
|
2316
2555
|
: [];
|
|
2556
|
+
|
|
2557
|
+
if (messages.length > 0) {
|
|
2558
|
+
return messages;
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
const legacyStub = legacyConversationStore(env, conversationId);
|
|
2562
|
+
const legacyResponse = await legacyStub.fetch(
|
|
2563
|
+
\`https://agentkit.internal/messages?conversationId=\${encodeURIComponent(conversationId)}\`,
|
|
2564
|
+
);
|
|
2565
|
+
|
|
2566
|
+
if (!legacyResponse.ok) {
|
|
2567
|
+
return [];
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
const legacyPayload = await legacyResponse.json();
|
|
2571
|
+
return Array.isArray(legacyPayload.messages)
|
|
2572
|
+
? legacyPayload.messages.filter((message) =>
|
|
2573
|
+
message &&
|
|
2574
|
+
typeof message === "object" &&
|
|
2575
|
+
(message.role === "user" || message.role === "assistant") &&
|
|
2576
|
+
typeof message.content === "string"
|
|
2577
|
+
)
|
|
2578
|
+
: [];
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
function hostedConversationStore(env) {
|
|
2582
|
+
const id = env.AGENTKIT_CONVERSATIONS.idFromName("agentkit-conversations");
|
|
2583
|
+
return env.AGENTKIT_CONVERSATIONS.get(id);
|
|
2584
|
+
}
|
|
2585
|
+
|
|
2586
|
+
function legacyConversationStore(env, conversationId) {
|
|
2587
|
+
const id = env.AGENTKIT_CONVERSATIONS.idFromName(conversationId);
|
|
2588
|
+
return env.AGENTKIT_CONVERSATIONS.get(id);
|
|
2317
2589
|
}
|
|
2318
2590
|
|
|
2319
2591
|
function normalizeConversationId(value) {
|
|
@@ -2590,6 +2862,18 @@ function titleFromMessage(content) {
|
|
|
2590
2862
|
const compact = content.split(/\\r?\\n/, 1)[0].replace(/\\s+/g, " ").trim();
|
|
2591
2863
|
return compact.length <= 80 ? compact : \`\${compact.slice(0, 77)}...\`;
|
|
2592
2864
|
}
|
|
2865
|
+
|
|
2866
|
+
function parseStoredJson(value, fallback) {
|
|
2867
|
+
if (typeof value !== "string") {
|
|
2868
|
+
return fallback;
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
try {
|
|
2872
|
+
return JSON.parse(value);
|
|
2873
|
+
} catch {
|
|
2874
|
+
return fallback;
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2593
2877
|
`;
|
|
2594
2878
|
}
|
|
2595
2879
|
|
|
@@ -2673,6 +2957,7 @@ CREATE TABLE IF NOT EXISTS tool_calls (
|
|
|
2673
2957
|
status TEXT NOT NULL,
|
|
2674
2958
|
input_json TEXT NOT NULL,
|
|
2675
2959
|
output_json TEXT,
|
|
2960
|
+
rendered_json TEXT,
|
|
2676
2961
|
error_message TEXT,
|
|
2677
2962
|
created_at TEXT NOT NULL,
|
|
2678
2963
|
completed_at TEXT
|