@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
package/src/runtime/inspect.ts
CHANGED
|
@@ -203,6 +203,7 @@ export function buildInspectState(
|
|
|
203
203
|
toolkits: integration.toolkits,
|
|
204
204
|
tools: integration.allowedTools,
|
|
205
205
|
userId: integration.userId,
|
|
206
|
+
confirmExternalWrites: integration.confirmExternalWrites !== false,
|
|
206
207
|
})),
|
|
207
208
|
channels: (capsule.config.channels ?? []).map((channel) => ({
|
|
208
209
|
name: channel.name,
|
|
@@ -20,6 +20,7 @@ export type ManagedComposioResolutionOptions = {
|
|
|
20
20
|
type ManagedComposioToolInput = {
|
|
21
21
|
toolSlug: string;
|
|
22
22
|
arguments: Record<string, unknown>;
|
|
23
|
+
confirmed?: boolean;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
type ManagedComposioToolOutput = {
|
|
@@ -32,6 +33,13 @@ type ManagedComposioToolOutput = {
|
|
|
32
33
|
userId: string;
|
|
33
34
|
};
|
|
34
35
|
|
|
36
|
+
type ComposioActionGuide = {
|
|
37
|
+
summary: string;
|
|
38
|
+
argumentNotes: string[];
|
|
39
|
+
dangerousDefaults?: string[];
|
|
40
|
+
examples?: Array<Record<string, unknown>>;
|
|
41
|
+
};
|
|
42
|
+
|
|
35
43
|
export function resolveManagedComposioIntegrations(
|
|
36
44
|
config: Pick<AgentConfig, "name" | "integrations">,
|
|
37
45
|
options: ManagedComposioResolutionOptions = {},
|
|
@@ -74,8 +82,13 @@ export function createManagedComposioTools(
|
|
|
74
82
|
|
|
75
83
|
const tool: AgentTool<ManagedComposioToolInput, ManagedComposioToolOutput> = {
|
|
76
84
|
name: MANAGED_COMPOSIO_TOOL_NAME,
|
|
77
|
-
description:
|
|
85
|
+
description: [
|
|
78
86
|
"Executes one explicitly allowed AgentKit-managed Composio action for this deployed agent. Use only for configured connected apps.",
|
|
87
|
+
integration.confirmExternalWrites === false
|
|
88
|
+
? "External write confirmation is disabled for this integration by agentkit.config.ts."
|
|
89
|
+
: "For write actions, pass confirmed: true only after the user confirms the exact external change.",
|
|
90
|
+
describeAllowedComposioActions(integration.allowedTools),
|
|
91
|
+
].join("\n\n"),
|
|
79
92
|
visibility: "user",
|
|
80
93
|
secrets: [MANAGED_COMPOSIO_API_KEY_SECRET],
|
|
81
94
|
permissions: integration.allowedTools.map((toolName) => `composio:${toolName.toLowerCase()}`),
|
|
@@ -91,7 +104,13 @@ export function createManagedComposioTools(
|
|
|
91
104
|
arguments: {
|
|
92
105
|
type: "object",
|
|
93
106
|
additionalProperties: true,
|
|
94
|
-
description:
|
|
107
|
+
description:
|
|
108
|
+
"Structured arguments for the selected Composio action. Use the action notes in the tool description; do not rely on Composio defaults for dates, times, durations, recipients, or write behavior.",
|
|
109
|
+
},
|
|
110
|
+
confirmed: {
|
|
111
|
+
type: "boolean",
|
|
112
|
+
description:
|
|
113
|
+
"Set true only after explicit user confirmation for external write actions such as create, update, delete, send, patch, move, insert, clear, remove, import, or quick add.",
|
|
95
114
|
},
|
|
96
115
|
},
|
|
97
116
|
required: ["toolSlug", "arguments"],
|
|
@@ -121,6 +140,9 @@ export function createManagedComposioTools(
|
|
|
121
140
|
);
|
|
122
141
|
}
|
|
123
142
|
|
|
143
|
+
validateComposioArguments(input.toolSlug, input.arguments);
|
|
144
|
+
validateComposioConfirmation(input.toolSlug, input.confirmed, integration);
|
|
145
|
+
|
|
124
146
|
const result = await executeComposioTool({
|
|
125
147
|
apiKey: ctx.secrets[MANAGED_COMPOSIO_API_KEY_SECRET],
|
|
126
148
|
userId: integration.userId,
|
|
@@ -173,6 +195,150 @@ function allowedComposioTools(integration: ComposioManagedIntegration): string[]
|
|
|
173
195
|
return Array.from(new Set(Object.values(integration.tools ?? {}).flat())).sort();
|
|
174
196
|
}
|
|
175
197
|
|
|
198
|
+
function describeAllowedComposioActions(actions: string[]): string {
|
|
199
|
+
const lines = ["Allowed Composio actions:"];
|
|
200
|
+
|
|
201
|
+
for (const action of actions) {
|
|
202
|
+
const guide = COMPOSIO_ACTION_GUIDES[action];
|
|
203
|
+
|
|
204
|
+
if (!guide) {
|
|
205
|
+
lines.push(`- ${action}: Pass explicit arguments from the current Composio action schema. Do not invent fields or rely on hidden defaults.`);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
lines.push(`- ${action}: ${guide.summary}`);
|
|
210
|
+
|
|
211
|
+
for (const note of guide.argumentNotes) {
|
|
212
|
+
lines.push(` - ${note}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (const warning of guide.dangerousDefaults ?? []) {
|
|
216
|
+
lines.push(` - Dangerous default: ${warning}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (const example of guide.examples ?? []) {
|
|
220
|
+
lines.push(` - Example arguments: ${JSON.stringify(example)}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return lines.join("\n");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function validateComposioArguments(toolSlug: string, args: Record<string, unknown>): void {
|
|
228
|
+
if (toolSlug !== "GOOGLECALENDAR_CREATE_EVENT") {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const start = args.start_datetime;
|
|
233
|
+
|
|
234
|
+
if (typeof start !== "string" || !isUtcDateTime(start)) {
|
|
235
|
+
throw new AgentKitError(
|
|
236
|
+
"composio_argument_invalid",
|
|
237
|
+
"GOOGLECALENDAR_CREATE_EVENT requires start_datetime as an explicit UTC RFC3339 timestamp ending in Z or +00:00. Convert user-local times using the runtime time zone before calling Composio.",
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const minutes = args.event_duration_minutes;
|
|
242
|
+
const hours = args.event_duration_hour;
|
|
243
|
+
|
|
244
|
+
if (!isPositiveNumber(minutes) && !isPositiveNumber(hours)) {
|
|
245
|
+
throw new AgentKitError(
|
|
246
|
+
"composio_argument_required",
|
|
247
|
+
"GOOGLECALENDAR_CREATE_EVENT requires explicit event_duration_minutes or event_duration_hour. Composio defaults event_duration_minutes to 30, so AgentKit blocks implicit duration.",
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function validateComposioConfirmation(
|
|
253
|
+
toolSlug: string,
|
|
254
|
+
confirmed: boolean | undefined,
|
|
255
|
+
integration: ComposioManagedIntegration,
|
|
256
|
+
): void {
|
|
257
|
+
if (integration.confirmExternalWrites === false || !isComposioWriteAction(toolSlug)) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (confirmed !== true) {
|
|
262
|
+
throw new AgentKitError(
|
|
263
|
+
"composio_confirmation_required",
|
|
264
|
+
`Composio action ${toolSlug} changes an external system. Ask the user to confirm the exact action and call again with confirmed: true.`,
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function isComposioWriteAction(toolSlug: string): boolean {
|
|
270
|
+
return /_(?:BATCH|CLEAR|CREATE|DELETE|DUPLICATE|IMPORT|INSERT|MOVE|PATCH|QUICK_ADD|REMOVE|REVOKE|SEND|UPDATE)(?:_|$)/.test(
|
|
271
|
+
toolSlug,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function isUtcDateTime(value: string): boolean {
|
|
276
|
+
return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|\+00:00)$/.test(value);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function isPositiveNumber(value: unknown): boolean {
|
|
280
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const COMPOSIO_ACTION_GUIDES: Record<string, ComposioActionGuide> = {
|
|
284
|
+
GOOGLECALENDAR_EVENTS_LIST: {
|
|
285
|
+
summary: "List events from a calendar before answering schedule/availability questions.",
|
|
286
|
+
argumentNotes: [
|
|
287
|
+
"calendarId is required by Composio; use primary unless the user selected a different calendar.",
|
|
288
|
+
"Use explicit timeMin and timeMax RFC3339 bounds for the requested window.",
|
|
289
|
+
"Pass timeZone when the user or business timezone matters.",
|
|
290
|
+
],
|
|
291
|
+
examples: [
|
|
292
|
+
{
|
|
293
|
+
calendarId: "primary",
|
|
294
|
+
timeMin: "2026-06-03T00:00:00-03:00",
|
|
295
|
+
timeMax: "2026-06-04T00:00:00-03:00",
|
|
296
|
+
singleEvents: true,
|
|
297
|
+
orderBy: "startTime",
|
|
298
|
+
timeZone: "America/Sao_Paulo",
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
GOOGLECALENDAR_CREATE_EVENT: {
|
|
303
|
+
summary: "Create an event only after confirming the exact title, date, start time, duration, timezone, and attendees/location when relevant.",
|
|
304
|
+
argumentNotes: [
|
|
305
|
+
"start_datetime is required and must be UTC RFC3339, for example 2026-06-03T15:00:00Z for 12:00 in America/Sao_Paulo.",
|
|
306
|
+
"calendar_id defaults to primary; pass it explicitly when known.",
|
|
307
|
+
"event_duration_minutes or event_duration_hour must be explicit.",
|
|
308
|
+
"Set timezone to the user/business IANA timezone when known.",
|
|
309
|
+
],
|
|
310
|
+
dangerousDefaults: [
|
|
311
|
+
"event_duration_minutes defaults to 30 if omitted.",
|
|
312
|
+
"calendar_id defaults to primary if omitted.",
|
|
313
|
+
],
|
|
314
|
+
examples: [
|
|
315
|
+
{
|
|
316
|
+
calendar_id: "primary",
|
|
317
|
+
summary: "Client call",
|
|
318
|
+
start_datetime: "2026-06-03T15:00:00Z",
|
|
319
|
+
event_duration_minutes: 60,
|
|
320
|
+
timezone: "America/Sao_Paulo",
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
},
|
|
324
|
+
GOOGLECALENDAR_UPDATE_EVENT: {
|
|
325
|
+
summary: "Update an existing event only after identifying the event and confirming the exact change.",
|
|
326
|
+
argumentNotes: [
|
|
327
|
+
"Read or find the event first so event_id/calendar_id are correct.",
|
|
328
|
+
"When changing time, use explicit UTC RFC3339 values and preserve duration unless the user changed it.",
|
|
329
|
+
"Do not infer cancellation/deletion from vague wording.",
|
|
330
|
+
],
|
|
331
|
+
},
|
|
332
|
+
GMAIL_FETCH_EMAILS: {
|
|
333
|
+
summary: "Fetch emails for read/search requests.",
|
|
334
|
+
argumentNotes: ["Use narrow query/window arguments when available; do not fetch broad mailbox history unnecessarily."],
|
|
335
|
+
},
|
|
336
|
+
GMAIL_SEND_EMAIL: {
|
|
337
|
+
summary: "Send email only after confirming recipients, subject, body, and attachments/links.",
|
|
338
|
+
argumentNotes: ["Pass recipient fields explicitly and avoid using draft-like placeholders in production sends."],
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
|
|
176
342
|
async function executeComposioTool(input: {
|
|
177
343
|
apiKey: string | undefined;
|
|
178
344
|
userId: string;
|
|
@@ -108,7 +108,25 @@ async function searchLexical(db: DatabaseRunner, query: string, limit: number):
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
async function searchLexicalFallback(db: DatabaseRunner, query: string, limit: number): Promise<KnowledgeSearchResult[]> {
|
|
111
|
-
const
|
|
111
|
+
const tokens = queryTokens(query);
|
|
112
|
+
|
|
113
|
+
if (tokens.length === 0) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const conditions = tokens
|
|
118
|
+
.map(
|
|
119
|
+
() => `(
|
|
120
|
+
lower(c.content) LIKE ? ESCAPE '\\'
|
|
121
|
+
OR lower(COALESCE(c.title, '')) LIKE ? ESCAPE '\\'
|
|
122
|
+
OR lower(COALESCE(c.section, '')) LIKE ? ESCAPE '\\'
|
|
123
|
+
)`,
|
|
124
|
+
)
|
|
125
|
+
.join(" AND ");
|
|
126
|
+
const args = tokens.flatMap((token) => {
|
|
127
|
+
const like = likePattern(token);
|
|
128
|
+
return [like, like, like];
|
|
129
|
+
});
|
|
112
130
|
const result = await db.query(
|
|
113
131
|
`
|
|
114
132
|
SELECT
|
|
@@ -121,13 +139,11 @@ async function searchLexicalFallback(db: DatabaseRunner, query: string, limit: n
|
|
|
121
139
|
s.source_key AS source_key
|
|
122
140
|
FROM agentkit_knowledge_chunks c
|
|
123
141
|
JOIN agentkit_knowledge_sources s ON s.id = c.source_id
|
|
124
|
-
WHERE
|
|
125
|
-
OR lower(COALESCE(c.title, '')) LIKE ?
|
|
126
|
-
OR lower(COALESCE(c.section, '')) LIKE ?
|
|
142
|
+
WHERE ${conditions}
|
|
127
143
|
ORDER BY c.created_at DESC, c.ordinal ASC
|
|
128
144
|
LIMIT ?
|
|
129
145
|
`,
|
|
130
|
-
[
|
|
146
|
+
[...args, limit],
|
|
131
147
|
);
|
|
132
148
|
|
|
133
149
|
return result.rows.map((row, index) => knowledgeSearchResultFromRow(row, lexicalScore(index), null));
|
|
@@ -269,6 +285,10 @@ function queryTokens(query: string): string[] {
|
|
|
269
285
|
return Array.from(new Set(query.toLowerCase().match(/[\p{L}\p{N}_-]+/gu) ?? [])).slice(0, 12);
|
|
270
286
|
}
|
|
271
287
|
|
|
288
|
+
function likePattern(token: string): string {
|
|
289
|
+
return `%${token.replace(/[\\%_]/g, (value) => `\\${value}`)}%`;
|
|
290
|
+
}
|
|
291
|
+
|
|
272
292
|
function parseEmbedding(value: unknown): number[] | null {
|
|
273
293
|
if (typeof value !== "string") {
|
|
274
294
|
return null;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export const KNOWLEDGE_MIGRATION_ID = "0006_create_knowledge_tables";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
type KnowledgeSchemaDatabase = {
|
|
4
|
+
exec(sql: string): unknown;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type KnowledgeLexicalIndexMode = "fts5" | "fallback";
|
|
8
|
+
|
|
9
|
+
export const KNOWLEDGE_BASE_SCHEMA_SQL = `
|
|
4
10
|
CREATE TABLE IF NOT EXISTS agentkit_knowledge_sources (
|
|
5
11
|
id TEXT PRIMARY KEY,
|
|
6
12
|
source_key TEXT NOT NULL UNIQUE,
|
|
@@ -43,7 +49,9 @@ export const KNOWLEDGE_SCHEMA_SQL = `
|
|
|
43
49
|
|
|
44
50
|
CREATE INDEX IF NOT EXISTS agentkit_knowledge_chunks_source_ordinal_idx
|
|
45
51
|
ON agentkit_knowledge_chunks(source_id, ordinal);
|
|
52
|
+
`;
|
|
46
53
|
|
|
54
|
+
export const KNOWLEDGE_FTS5_SCHEMA_SQL = `
|
|
47
55
|
CREATE VIRTUAL TABLE IF NOT EXISTS agentkit_knowledge_fts
|
|
48
56
|
USING fts5(
|
|
49
57
|
chunk_id UNINDEXED,
|
|
@@ -54,3 +62,39 @@ export const KNOWLEDGE_SCHEMA_SQL = `
|
|
|
54
62
|
tokenize='unicode61'
|
|
55
63
|
);
|
|
56
64
|
`;
|
|
65
|
+
|
|
66
|
+
export const KNOWLEDGE_FTS_FALLBACK_SCHEMA_SQL = `
|
|
67
|
+
CREATE TABLE IF NOT EXISTS agentkit_knowledge_fts (
|
|
68
|
+
chunk_id TEXT PRIMARY KEY,
|
|
69
|
+
source_id TEXT NOT NULL,
|
|
70
|
+
title TEXT,
|
|
71
|
+
section TEXT,
|
|
72
|
+
content TEXT NOT NULL
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
CREATE INDEX IF NOT EXISTS agentkit_knowledge_fts_source_idx
|
|
76
|
+
ON agentkit_knowledge_fts(source_id);
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
export const KNOWLEDGE_SCHEMA_SQL = `${KNOWLEDGE_BASE_SCHEMA_SQL}\n${KNOWLEDGE_FTS5_SCHEMA_SQL}`;
|
|
80
|
+
|
|
81
|
+
export function applyKnowledgeSchema(db: KnowledgeSchemaDatabase): KnowledgeLexicalIndexMode {
|
|
82
|
+
db.exec(KNOWLEDGE_BASE_SCHEMA_SQL);
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
db.exec(KNOWLEDGE_FTS5_SCHEMA_SQL);
|
|
86
|
+
return "fts5";
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (!isMissingFts5ModuleError(error)) {
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
db.exec(KNOWLEDGE_FTS_FALLBACK_SCHEMA_SQL);
|
|
94
|
+
return "fallback";
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isMissingFts5ModuleError(error: unknown): boolean {
|
|
98
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
99
|
+
return /no such module:\s*fts5/i.test(message) || /unknown module:\s*fts5/i.test(message);
|
|
100
|
+
}
|
|
@@ -35,6 +35,60 @@ export async function assertRuntimeContract(
|
|
|
35
35
|
expect(inspect.status).toBe(200);
|
|
36
36
|
expect(inspect.body).toMatchObject({ agent: options.expectedAgentName });
|
|
37
37
|
|
|
38
|
+
if (options.auth) {
|
|
39
|
+
const missingAdmin = await fetchJson(`${baseUrl}/_agentkit`);
|
|
40
|
+
expect(missingAdmin.status).toBe(401);
|
|
41
|
+
expect(missingAdmin.body.error.code).toBe("unauthorized");
|
|
42
|
+
|
|
43
|
+
const invalidAdmin = await fetchJson(`${baseUrl}/_agentkit`, {
|
|
44
|
+
headers: { Authorization: "Bearer invalid-admin-token" },
|
|
45
|
+
});
|
|
46
|
+
expect(invalidAdmin.status).toBe(401);
|
|
47
|
+
expect(invalidAdmin.body.error.code).toBe("unauthorized");
|
|
48
|
+
|
|
49
|
+
const missingChat = await fetchJson(`${baseUrl}/chat`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { "content-type": "application/json" },
|
|
52
|
+
body: JSON.stringify({ message: "hello" }),
|
|
53
|
+
});
|
|
54
|
+
expect(missingChat.status).toBe(401);
|
|
55
|
+
expect(missingChat.body.error.code).toBe("unauthorized");
|
|
56
|
+
|
|
57
|
+
const invalidChat = await fetchJson(`${baseUrl}/chat`, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: { "content-type": "application/json", Authorization: "Bearer invalid-chat-token" },
|
|
60
|
+
body: JSON.stringify({ message: "hello" }),
|
|
61
|
+
});
|
|
62
|
+
expect(invalidChat.status).toBe(401);
|
|
63
|
+
expect(invalidChat.body.error.code).toBe("unauthorized");
|
|
64
|
+
|
|
65
|
+
const missingTool = await fetchJson(`${baseUrl}/tools/${encodeURIComponent(options.tool.name)}`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: { "content-type": "application/json" },
|
|
68
|
+
body: JSON.stringify({ input: options.tool.input }),
|
|
69
|
+
});
|
|
70
|
+
expect(missingTool.status).toBe(401);
|
|
71
|
+
expect(missingTool.body.error.code).toBe("unauthorized");
|
|
72
|
+
|
|
73
|
+
const invalidTool = await fetchJson(`${baseUrl}/tools/${encodeURIComponent(options.tool.name)}`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: { "content-type": "application/json", Authorization: "Bearer invalid-admin-token" },
|
|
76
|
+
body: JSON.stringify({ input: options.tool.input }),
|
|
77
|
+
});
|
|
78
|
+
expect(invalidTool.status).toBe(401);
|
|
79
|
+
expect(invalidTool.body.error.code).toBe("unauthorized");
|
|
80
|
+
|
|
81
|
+
const missingConversations = await fetchJson(`${baseUrl}/v1/conversations`);
|
|
82
|
+
expect(missingConversations.status).toBe(401);
|
|
83
|
+
expect(missingConversations.body.error.code).toBe("unauthorized");
|
|
84
|
+
|
|
85
|
+
const invalidConversations = await fetchJson(`${baseUrl}/v1/conversations`, {
|
|
86
|
+
headers: { Authorization: "Bearer invalid-admin-token" },
|
|
87
|
+
});
|
|
88
|
+
expect(invalidConversations.status).toBe(401);
|
|
89
|
+
expect(invalidConversations.body.error.code).toBe("unauthorized");
|
|
90
|
+
}
|
|
91
|
+
|
|
38
92
|
const unauthorized = await fetchJson(`${baseUrl}/chat`, {
|
|
39
93
|
method: "POST",
|
|
40
94
|
headers: withHeaders({ "content-type": "application/json" }, options.auth?.chat),
|