@andreprado/agentkit 0.1.0-alpha.5 → 0.1.0-alpha.7
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 +9 -0
- package/docs/guides/add-channel.md +25 -0
- package/docs/guides/add-knowledge.md +134 -0
- package/docs/guides/agentkit-skills-architecture.md +471 -0
- package/docs/guides/channels-production-handoff.md +2 -0
- package/docs/guides/connect-telegram.md +17 -0
- package/docs/guides/connect-whatsapp-zapster.md +16 -0
- package/docs/guides/create-agent.md +10 -1
- package/docs/guides/run-evals.md +36 -1
- package/docs/llms-full.txt +90 -1
- package/docs/llms.txt +9 -2
- package/package.json +2 -1
- package/src/cli/cloud-client.ts +10 -2
- package/src/cli/commands/channels.ts +67 -3
- package/src/cli/commands/knowledge.ts +136 -0
- package/src/cli/deploy-chat-ui.ts +7 -0
- package/src/cli/deploy-readiness.ts +19 -0
- package/src/cli/help.ts +26 -2
- package/src/cli/index.ts +140 -8
- package/src/cloud/artifact.ts +92 -1
- package/src/cloud/contracts.ts +16 -0
- package/src/create-project.ts +38 -6
- package/src/index.ts +142 -1
- package/src/providers/pi.ts +1 -1
- package/src/providers/test.ts +1 -1
- package/src/runtime/channel-buffer.ts +30 -0
- package/src/runtime/channels.ts +1 -0
- package/src/runtime/chat.ts +21 -2
- package/src/runtime/config.ts +175 -0
- package/src/runtime/core/manifest.ts +37 -0
- package/src/runtime/database.ts +93 -2
- package/src/runtime/db-commands.ts +9 -0
- package/src/runtime/deploy-readiness.ts +12 -0
- package/src/runtime/dev-server.ts +201 -11
- package/src/runtime/evals.ts +210 -20
- package/src/runtime/inspect.ts +39 -0
- package/src/runtime/knowledge/chunk.ts +333 -0
- package/src/runtime/knowledge/config.ts +135 -0
- package/src/runtime/knowledge/embeddings.ts +133 -0
- package/src/runtime/knowledge/ingest.ts +521 -0
- package/src/runtime/knowledge/prompt-policy.ts +30 -0
- package/src/runtime/knowledge/retrieve.ts +283 -0
- package/src/runtime/knowledge/schema.ts +56 -0
- package/src/runtime/knowledge/tool.ts +64 -0
- package/src/runtime/knowledge/vector.ts +258 -0
- package/src/runtime/spec.ts +152 -0
- package/src/runtime/sync.ts +144 -0
- package/src/runtime/targets/cloudflare/build.ts +514 -4
- package/src/runtime/tools.ts +121 -1
- package/src/runtime/traces.ts +41 -0
- package/src/storage/sqlite.ts +141 -0
- package/src/templates/blank.ts +16 -5
- package/src/templates/dentista.ts +17 -2
- package/src/templates/skills/agentkit-build-agent/SKILL.md +51 -0
- package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md +20 -0
- package/src/templates/skills/agentkit-build-agent/templates/sales-qualifier.instructions.md +17 -0
- package/src/templates/skills/agentkit-build-agent/templates/support-agent.instructions.md +16 -0
- package/src/templates/skills/agentkit-capsule/SKILL.md +62 -0
- package/src/templates/skills/agentkit-capsule/references/docs-router.md +15 -0
- package/src/templates/skills/agentkit-channels/SKILL.md +62 -0
- package/src/templates/skills/agentkit-channels/references/channel-buffering.md +58 -0
- package/src/templates/skills/agentkit-channels/references/channel-debugging.md +37 -0
- package/src/templates/skills/agentkit-channels/references/telegram.md +37 -0
- package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +37 -0
- package/src/templates/skills/agentkit-database/SKILL.md +45 -0
- package/src/templates/skills/agentkit-database/templates/appointments.schema.sql +15 -0
- package/src/templates/skills/agentkit-database/templates/leads.schema.sql +17 -0
- package/src/templates/skills/agentkit-deploy/SKILL.md +44 -0
- package/src/templates/skills/agentkit-evals/SKILL.md +60 -0
- package/src/templates/skills/agentkit-evals/templates/multi-turn.eval.md +22 -0
- package/src/templates/skills/agentkit-evals/templates/no-leak.eval.md +14 -0
- package/src/templates/skills/agentkit-evals/templates/smoke.eval.md +14 -0
- package/src/templates/skills/agentkit-evals/templates/tool-call.eval.md +18 -0
- package/src/templates/skills/agentkit-knowledge/SKILL.md +40 -0
- package/src/templates/skills/agentkit-knowledge/templates/faq.md +14 -0
- package/src/templates/skills/agentkit-knowledge/templates/policies.md +14 -0
- package/src/templates/skills/agentkit-knowledge/templates/prices.csv +3 -0
- package/src/templates/skills/agentkit-prompts/SKILL.md +45 -0
- package/src/templates/skills/agentkit-prompts/templates/knowledge-grounded-faq.instructions.md +11 -0
- package/src/templates/skills/agentkit-provider/SKILL.md +57 -0
- package/src/templates/skills/agentkit-security/SKILL.md +55 -0
- package/src/templates/skills/agentkit-tools/SKILL.md +36 -0
- package/src/templates/skills/agentkit-tools/examples/database-write.tool.md +35 -0
- package/src/templates/skills/agentkit-tools/examples/eval-safe-external-action.tool.md +37 -0
- package/src/templates/skills/agentkit-tools/examples/lookup-order.tool.md +46 -0
- package/src/templates/skills/agentkit-troubleshooting/SKILL.md +52 -0
- package/src/templates/support.ts +15 -4
package/src/index.ts
CHANGED
|
@@ -17,6 +17,28 @@ export type ChannelLimits = {
|
|
|
17
17
|
usdPerDay?: number;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
export type ChannelBufferMode = "off" | "debounce";
|
|
21
|
+
|
|
22
|
+
export type ChannelBufferInput = {
|
|
23
|
+
mode?: ChannelBufferMode;
|
|
24
|
+
quietWindowMs?: number;
|
|
25
|
+
maxWaitMs?: number;
|
|
26
|
+
maxMessages?: number;
|
|
27
|
+
maxChars?: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type ChannelBufferConfig =
|
|
31
|
+
| {
|
|
32
|
+
mode: "off";
|
|
33
|
+
}
|
|
34
|
+
| {
|
|
35
|
+
mode: "debounce";
|
|
36
|
+
quietWindowMs: number;
|
|
37
|
+
maxWaitMs: number;
|
|
38
|
+
maxMessages: number;
|
|
39
|
+
maxChars: number;
|
|
40
|
+
};
|
|
41
|
+
|
|
20
42
|
export type WebsiteChannelAccess = {
|
|
21
43
|
mode: "token";
|
|
22
44
|
};
|
|
@@ -26,6 +48,7 @@ export type WebsiteChannelInput = {
|
|
|
26
48
|
access?: WebsiteChannelAccess;
|
|
27
49
|
secrets?: string[];
|
|
28
50
|
limits?: ChannelLimits;
|
|
51
|
+
buffer?: ChannelBufferInput;
|
|
29
52
|
};
|
|
30
53
|
|
|
31
54
|
export type WebsiteChannelConfig = {
|
|
@@ -35,6 +58,7 @@ export type WebsiteChannelConfig = {
|
|
|
35
58
|
access: WebsiteChannelAccess;
|
|
36
59
|
secrets: string[];
|
|
37
60
|
limits?: ChannelLimits;
|
|
61
|
+
buffer?: ChannelBufferConfig;
|
|
38
62
|
};
|
|
39
63
|
|
|
40
64
|
export type TelegramChannelInput = {
|
|
@@ -42,6 +66,7 @@ export type TelegramChannelInput = {
|
|
|
42
66
|
secrets?: string[];
|
|
43
67
|
allowedUpdates?: TelegramAllowedUpdate[];
|
|
44
68
|
limits?: ChannelLimits;
|
|
69
|
+
buffer?: ChannelBufferInput;
|
|
45
70
|
};
|
|
46
71
|
|
|
47
72
|
export type TelegramChannelConfig = {
|
|
@@ -51,6 +76,7 @@ export type TelegramChannelConfig = {
|
|
|
51
76
|
secrets: string[];
|
|
52
77
|
allowedUpdates: TelegramAllowedUpdate[];
|
|
53
78
|
limits?: ChannelLimits;
|
|
79
|
+
buffer?: ChannelBufferConfig;
|
|
54
80
|
};
|
|
55
81
|
|
|
56
82
|
export type WhatsappChannelInput = {
|
|
@@ -58,6 +84,7 @@ export type WhatsappChannelInput = {
|
|
|
58
84
|
provider: WhatsappChannelProvider;
|
|
59
85
|
secrets?: string[];
|
|
60
86
|
limits?: ChannelLimits;
|
|
87
|
+
buffer?: ChannelBufferInput;
|
|
61
88
|
};
|
|
62
89
|
|
|
63
90
|
export type WhatsappChannelConfig = {
|
|
@@ -66,6 +93,7 @@ export type WhatsappChannelConfig = {
|
|
|
66
93
|
name: string;
|
|
67
94
|
secrets: string[];
|
|
68
95
|
limits?: ChannelLimits;
|
|
96
|
+
buffer?: ChannelBufferConfig;
|
|
69
97
|
};
|
|
70
98
|
|
|
71
99
|
export type AgentChannel = WebsiteChannelConfig | TelegramChannelConfig | WhatsappChannelConfig;
|
|
@@ -77,6 +105,7 @@ export type AgentDatabaseConfig =
|
|
|
77
105
|
| {
|
|
78
106
|
driver: "turso";
|
|
79
107
|
schema?: string;
|
|
108
|
+
migrations?: string;
|
|
80
109
|
};
|
|
81
110
|
|
|
82
111
|
export type AgentFilesConfig =
|
|
@@ -90,6 +119,37 @@ export type AgentFilesConfig =
|
|
|
90
119
|
maxUploadBytes?: number;
|
|
91
120
|
};
|
|
92
121
|
|
|
122
|
+
export type AgentKnowledgeSource =
|
|
123
|
+
| string
|
|
124
|
+
| {
|
|
125
|
+
path: string;
|
|
126
|
+
title?: string;
|
|
127
|
+
}
|
|
128
|
+
| {
|
|
129
|
+
url: string;
|
|
130
|
+
title?: string;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export type AgentKnowledgeEmbeddingProvider = "none" | "test" | "openai";
|
|
134
|
+
|
|
135
|
+
export type AgentKnowledgeEmbeddingConfig = {
|
|
136
|
+
provider?: AgentKnowledgeEmbeddingProvider;
|
|
137
|
+
model?: string;
|
|
138
|
+
dimensions?: number;
|
|
139
|
+
secret?: string;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export type AgentKnowledgeRetrievalConfig = {
|
|
143
|
+
topK?: number;
|
|
144
|
+
hybrid?: boolean;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export type AgentKnowledgeConfig = {
|
|
148
|
+
sources?: AgentKnowledgeSource[];
|
|
149
|
+
embedding?: AgentKnowledgeEmbeddingConfig;
|
|
150
|
+
retrieval?: AgentKnowledgeRetrievalConfig;
|
|
151
|
+
};
|
|
152
|
+
|
|
93
153
|
export type JsonSchema = {
|
|
94
154
|
type: string | string[];
|
|
95
155
|
properties?: Record<string, JsonSchema>;
|
|
@@ -119,9 +179,42 @@ export type DatabaseRunner = {
|
|
|
119
179
|
batch(statements: DatabaseStatement[]): Promise<DatabaseResult[]>;
|
|
120
180
|
};
|
|
121
181
|
|
|
182
|
+
export type ToolRenderField = {
|
|
183
|
+
label: string;
|
|
184
|
+
value: string;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export type ToolRenderAction = {
|
|
188
|
+
label: string;
|
|
189
|
+
href?: string;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
export type ToolRenderBlock =
|
|
193
|
+
| {
|
|
194
|
+
type: "text";
|
|
195
|
+
text: string;
|
|
196
|
+
}
|
|
197
|
+
| {
|
|
198
|
+
type: "card";
|
|
199
|
+
title: string;
|
|
200
|
+
subtitle?: string;
|
|
201
|
+
fields?: ToolRenderField[];
|
|
202
|
+
actions?: ToolRenderAction[];
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export type ToolRenderResult = {
|
|
206
|
+
text: string;
|
|
207
|
+
blocks?: ToolRenderBlock[];
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export type ToolRenderContext<Input = unknown> = {
|
|
211
|
+
input: Input;
|
|
212
|
+
runtime: ToolRuntimeContext;
|
|
213
|
+
};
|
|
214
|
+
|
|
122
215
|
export type ToolRuntimeContext = {
|
|
123
216
|
environment: "local" | "hosted" | "eval" | "test";
|
|
124
|
-
invocation: "chat" | "tool" | "dev" | "channel" | "eval";
|
|
217
|
+
invocation: "chat" | "tool" | "dev" | "channel" | "eval" | "sync";
|
|
125
218
|
target: "bun" | "cloudflare";
|
|
126
219
|
database: "sqlite" | "turso" | "none";
|
|
127
220
|
};
|
|
@@ -137,6 +230,13 @@ export type ToolContext = {
|
|
|
137
230
|
};
|
|
138
231
|
};
|
|
139
232
|
|
|
233
|
+
export type SyncContext = {
|
|
234
|
+
env: Record<string, string | undefined>;
|
|
235
|
+
database: DatabaseRunner;
|
|
236
|
+
db: DatabaseRunner;
|
|
237
|
+
runtime: ToolRuntimeContext;
|
|
238
|
+
};
|
|
239
|
+
|
|
140
240
|
export type AgentTool<Input = unknown, Output = unknown> = {
|
|
141
241
|
name: string;
|
|
142
242
|
description: string;
|
|
@@ -147,6 +247,7 @@ export type AgentTool<Input = unknown, Output = unknown> = {
|
|
|
147
247
|
permissions?: string[];
|
|
148
248
|
timeoutMs?: number;
|
|
149
249
|
execute(input: Input, ctx: ToolContext): Promise<Output> | Output;
|
|
250
|
+
render?(output: Output, ctx: ToolRenderContext<Input>): string | ToolRenderResult;
|
|
150
251
|
};
|
|
151
252
|
|
|
152
253
|
export type AgentConfig = {
|
|
@@ -157,6 +258,7 @@ export type AgentConfig = {
|
|
|
157
258
|
secrets: string[];
|
|
158
259
|
tools?: AgentTool[];
|
|
159
260
|
channels?: AgentChannel[];
|
|
261
|
+
knowledge?: AgentKnowledgeConfig;
|
|
160
262
|
access: {
|
|
161
263
|
mode: AccessMode;
|
|
162
264
|
};
|
|
@@ -184,6 +286,7 @@ export function websiteChannel(input: WebsiteChannelInput): WebsiteChannelConfig
|
|
|
184
286
|
access: input.access ?? { mode: "token" },
|
|
185
287
|
secrets: normalizeChannelSecrets(input.secrets ?? ["AGENTKIT_WEBSITE_CHANNEL_TOKEN"], "website channel"),
|
|
186
288
|
...(input.limits ? { limits: input.limits } : {}),
|
|
289
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "website channel") } : {}),
|
|
187
290
|
};
|
|
188
291
|
}
|
|
189
292
|
|
|
@@ -198,6 +301,7 @@ export function telegramChannel(input: TelegramChannelInput): TelegramChannelCon
|
|
|
198
301
|
),
|
|
199
302
|
allowedUpdates: input.allowedUpdates ?? ["message"],
|
|
200
303
|
...(input.limits ? { limits: input.limits } : {}),
|
|
304
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "telegram channel") } : {}),
|
|
201
305
|
};
|
|
202
306
|
}
|
|
203
307
|
|
|
@@ -211,6 +315,7 @@ export function whatsappChannel(input: WhatsappChannelInput): WhatsappChannelCon
|
|
|
211
315
|
`${input.provider} whatsapp channel`,
|
|
212
316
|
),
|
|
213
317
|
...(input.limits ? { limits: input.limits } : {}),
|
|
318
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, `${input.provider} whatsapp channel`) } : {}),
|
|
214
319
|
};
|
|
215
320
|
}
|
|
216
321
|
|
|
@@ -236,10 +341,46 @@ function normalizeChannelSecrets(secrets: string[], context: string): string[] {
|
|
|
236
341
|
return Array.from(uniqueSecrets).sort();
|
|
237
342
|
}
|
|
238
343
|
|
|
344
|
+
function normalizeChannelBuffer(input: ChannelBufferInput, context: string): ChannelBufferConfig {
|
|
345
|
+
if (input.mode === "off") {
|
|
346
|
+
return { mode: "off" };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (input.mode !== undefined && input.mode !== "debounce") {
|
|
350
|
+
throw new Error(`${context} buffer.mode must be "off" or "debounce".`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const buffer: ChannelBufferConfig = {
|
|
354
|
+
mode: "debounce",
|
|
355
|
+
quietWindowMs: input.quietWindowMs ?? 2500,
|
|
356
|
+
maxWaitMs: input.maxWaitMs ?? 12000,
|
|
357
|
+
maxMessages: input.maxMessages ?? 20,
|
|
358
|
+
maxChars: input.maxChars ?? 8000,
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
validatePositiveInteger(buffer.quietWindowMs, `${context} buffer.quietWindowMs`);
|
|
362
|
+
validatePositiveInteger(buffer.maxWaitMs, `${context} buffer.maxWaitMs`);
|
|
363
|
+
validatePositiveInteger(buffer.maxMessages, `${context} buffer.maxMessages`);
|
|
364
|
+
validatePositiveInteger(buffer.maxChars, `${context} buffer.maxChars`);
|
|
365
|
+
|
|
366
|
+
if (buffer.maxWaitMs < buffer.quietWindowMs) {
|
|
367
|
+
throw new Error(`${context} buffer.maxWaitMs must be greater than or equal to buffer.quietWindowMs.`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return buffer;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function validatePositiveInteger(value: number, field: string): void {
|
|
374
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
375
|
+
throw new Error(`${field} must be a positive integer.`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
239
379
|
export { loadAgentCapsule, findAgentCapsuleRoot } from "./runtime/config";
|
|
240
380
|
export { runAgentMessage, runAgentMessageFromCwd } from "./runtime/chat";
|
|
241
381
|
export { listConversationsFromCwd, getConversationFromCwd } from "./runtime/conversations";
|
|
242
382
|
export { runEvalsFromCwd } from "./runtime/evals";
|
|
383
|
+
export { getConversationTraceFromCwd } from "./runtime/traces";
|
|
243
384
|
export { runToolFromCwd } from "./runtime/tool-runner";
|
|
244
385
|
export { startAgentDevServer } from "./runtime/dev-server";
|
|
245
386
|
export { inspectAgentCapsule } from "./runtime/inspect";
|
package/src/providers/pi.ts
CHANGED
|
@@ -97,7 +97,7 @@ async function runPiProvider(input: ProviderRunInput): Promise<ProviderRunResult
|
|
|
97
97
|
content: [
|
|
98
98
|
{
|
|
99
99
|
type: "text",
|
|
100
|
-
text: JSON.stringify(result.output),
|
|
100
|
+
text: result.rendered?.text ?? JSON.stringify(result.output),
|
|
101
101
|
},
|
|
102
102
|
],
|
|
103
103
|
isError: false,
|
package/src/providers/test.ts
CHANGED
|
@@ -29,7 +29,7 @@ export const testProviderAdapter: ProviderAdapter = {
|
|
|
29
29
|
content:
|
|
30
30
|
toolResult.visibility === "internal"
|
|
31
31
|
? `Tool ${toolResult.name}: completed`
|
|
32
|
-
: `Tool ${toolResult.name}: ${JSON.stringify(toolResult.output)}`,
|
|
32
|
+
: toolResult.rendered?.text ?? `Tool ${toolResult.name}: ${JSON.stringify(toolResult.output)}`,
|
|
33
33
|
},
|
|
34
34
|
raw: {
|
|
35
35
|
toolCalls: [toolResult],
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ChannelBufferConfig, ChannelType } from "../index";
|
|
2
|
+
|
|
3
|
+
export type ChannelBufferCarrier = {
|
|
4
|
+
type: ChannelType;
|
|
5
|
+
buffer?: ChannelBufferConfig;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type ChannelBufferedMessage = {
|
|
9
|
+
content: string;
|
|
10
|
+
receivedAt: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function resolveChannelBuffer(channel: ChannelBufferCarrier): ChannelBufferConfig {
|
|
14
|
+
return channel.buffer ?? { mode: "off" };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isChannelBufferEnabled(channel: ChannelBufferCarrier): boolean {
|
|
18
|
+
return resolveChannelBuffer(channel).mode === "debounce";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function renderBufferedChannelMessage(messages: ChannelBufferedMessage[]): string {
|
|
22
|
+
if (messages.length === 1) {
|
|
23
|
+
return messages[0]?.content ?? "";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const lines = messages.map((message, index) => `${index + 1}. ${message.content}`);
|
|
27
|
+
|
|
28
|
+
return `The client sent ${messages.length} messages in one burst. Answer once, using the full context below:\n\n${lines.join("\n")}`;
|
|
29
|
+
}
|
|
30
|
+
|
package/src/runtime/channels.ts
CHANGED
package/src/runtime/chat.ts
CHANGED
|
@@ -7,6 +7,9 @@ import { loadAgentCapsule } from "./config";
|
|
|
7
7
|
import { openPreparedCapsuleStore } from "./database";
|
|
8
8
|
import { loadCapsuleEnv } from "./env";
|
|
9
9
|
import { AgentKitError, isAgentKitError } from "./errors";
|
|
10
|
+
import { syncConfiguredKnowledgeSources } from "./knowledge/ingest";
|
|
11
|
+
import { appendKnowledgePromptPolicy } from "./knowledge/prompt-policy";
|
|
12
|
+
import { createKnowledgeSearchTool } from "./knowledge/tool";
|
|
10
13
|
import { createToolRuntime } from "./tools";
|
|
11
14
|
|
|
12
15
|
export type RunAgentMessageOptions = {
|
|
@@ -37,6 +40,7 @@ export async function runAgentMessage(
|
|
|
37
40
|
|
|
38
41
|
const adapter = getProviderAdapter(capsule.config.provider);
|
|
39
42
|
const env = await loadCapsuleEnv(capsule.root);
|
|
43
|
+
await syncConfiguredKnowledgeSources(capsule);
|
|
40
44
|
const { store } = await openPreparedCapsuleStore(capsule);
|
|
41
45
|
const conversationId = normalizeConversationId(options.conversationId);
|
|
42
46
|
const { conversation, previousMessages } = resolveConversation(store, {
|
|
@@ -55,8 +59,9 @@ export async function runAgentMessage(
|
|
|
55
59
|
provider: capsule.config.provider.name,
|
|
56
60
|
model: capsule.config.provider.model,
|
|
57
61
|
});
|
|
62
|
+
const runtimeTools = withKnowledgeTools(capsule);
|
|
58
63
|
const toolRuntime = createToolRuntime({
|
|
59
|
-
tools:
|
|
64
|
+
tools: runtimeTools,
|
|
60
65
|
store,
|
|
61
66
|
runId: run.id,
|
|
62
67
|
conversationId: conversation.id,
|
|
@@ -78,7 +83,10 @@ export async function runAgentMessage(
|
|
|
78
83
|
runtime: capsule.config.runtime,
|
|
79
84
|
provider: capsule.config.provider,
|
|
80
85
|
},
|
|
81
|
-
instructions: withToolVisibilityInstructions(
|
|
86
|
+
instructions: withToolVisibilityInstructions(
|
|
87
|
+
appendKnowledgePromptPolicy(capsule.instructions, capsule.config),
|
|
88
|
+
runtimeTools,
|
|
89
|
+
),
|
|
82
90
|
messages,
|
|
83
91
|
tools: toolRuntime.definitions,
|
|
84
92
|
toolRuntime,
|
|
@@ -119,6 +127,17 @@ export async function runAgentMessage(
|
|
|
119
127
|
}
|
|
120
128
|
}
|
|
121
129
|
|
|
130
|
+
function withKnowledgeTools(capsule: LoadedAgentCapsule): NonNullable<LoadedAgentCapsule["config"]["tools"]> {
|
|
131
|
+
const tools = [...(capsule.config.tools ?? [])];
|
|
132
|
+
const knowledgeTool = createKnowledgeSearchTool(capsule);
|
|
133
|
+
|
|
134
|
+
if (knowledgeTool) {
|
|
135
|
+
return [knowledgeTool, ...tools];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return tools;
|
|
139
|
+
}
|
|
140
|
+
|
|
122
141
|
function resolveConversation(
|
|
123
142
|
store: Awaited<ReturnType<typeof openPreparedCapsuleStore>>["store"],
|
|
124
143
|
input: {
|
package/src/runtime/config.ts
CHANGED
|
@@ -14,6 +14,8 @@ import type {
|
|
|
14
14
|
ChannelProvider,
|
|
15
15
|
ChannelType,
|
|
16
16
|
TelegramAllowedUpdate,
|
|
17
|
+
AgentKnowledgeEmbeddingProvider,
|
|
18
|
+
ChannelBufferMode,
|
|
17
19
|
} from "../index";
|
|
18
20
|
import { AgentKitError } from "./errors";
|
|
19
21
|
|
|
@@ -24,7 +26,9 @@ const ACCESS_MODES = new Set<AccessMode>(["private", "token", "public"]);
|
|
|
24
26
|
const TOOL_VISIBILITIES = new Set<ToolVisibility>(["user", "internal"]);
|
|
25
27
|
const CHANNEL_TYPES = new Set<ChannelType>(["website", "telegram", "whatsapp"]);
|
|
26
28
|
const CHANNEL_PROVIDERS = new Set<ChannelProvider>(["agentkit", "telegram", "zapster", "meta"]);
|
|
29
|
+
const CHANNEL_BUFFER_MODES = new Set<ChannelBufferMode>(["off", "debounce"]);
|
|
27
30
|
const TELEGRAM_ALLOWED_UPDATES = new Set<TelegramAllowedUpdate>(["message"]);
|
|
31
|
+
const KNOWLEDGE_EMBEDDING_PROVIDERS = new Set<AgentKnowledgeEmbeddingProvider>(["none", "test", "openai"]);
|
|
28
32
|
const CHANNEL_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
29
33
|
const SECRET_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
|
|
30
34
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -205,6 +209,7 @@ function validateAgentConfig(value: unknown): asserts value is AgentConfig {
|
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
validateChannels(value.channels, value.runtime as AgentRuntime);
|
|
212
|
+
validateKnowledgeConfig(value.knowledge);
|
|
208
213
|
|
|
209
214
|
if (!isRecord(value.access) || !ACCESS_MODES.has(value.access.mode as AccessMode)) {
|
|
210
215
|
throw invalidConfig('access.mode must be "private", "token", or "public".');
|
|
@@ -226,6 +231,134 @@ function validateAgentConfig(value: unknown): asserts value is AgentConfig {
|
|
|
226
231
|
validateFilesConfig(value.storage.files);
|
|
227
232
|
}
|
|
228
233
|
|
|
234
|
+
function validateKnowledgeConfig(value: unknown): void {
|
|
235
|
+
if (value === undefined) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!isRecord(value)) {
|
|
240
|
+
throw invalidConfig("knowledge must be an object when provided.");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (value.sources !== undefined) {
|
|
244
|
+
if (!Array.isArray(value.sources)) {
|
|
245
|
+
throw invalidConfig("knowledge.sources must be an array when provided.");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (const [index, source] of value.sources.entries()) {
|
|
249
|
+
validateKnowledgeSource(source, index);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (value.embedding !== undefined) {
|
|
254
|
+
validateKnowledgeEmbedding(value.embedding);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (value.retrieval !== undefined) {
|
|
258
|
+
validateKnowledgeRetrieval(value.retrieval);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function validateKnowledgeSource(value: unknown, index: number): void {
|
|
263
|
+
if (typeof value === "string") {
|
|
264
|
+
expectString(value, `knowledge.sources[${index}]`);
|
|
265
|
+
validateKnowledgeSourceReference(value, `knowledge.sources[${index}]`);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (!isRecord(value)) {
|
|
270
|
+
throw invalidConfig(`knowledge.sources[${index}] must be a path string or an object with path or url.`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const hasPath = "path" in value;
|
|
274
|
+
const hasUrl = "url" in value;
|
|
275
|
+
|
|
276
|
+
if (hasPath === hasUrl) {
|
|
277
|
+
throw invalidConfig(`knowledge.sources[${index}] must set exactly one of path or url.`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (hasPath) {
|
|
281
|
+
expectString(value.path, `knowledge.sources[${index}].path`);
|
|
282
|
+
validateKnowledgeSourceReference(value.path, `knowledge.sources[${index}].path`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (hasUrl) {
|
|
286
|
+
expectString(value.url, `knowledge.sources[${index}].url`);
|
|
287
|
+
validateKnowledgeUrl(value.url, `knowledge.sources[${index}].url`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (value.title !== undefined) {
|
|
291
|
+
expectString(value.title, `knowledge.sources[${index}].title`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function validateKnowledgeSourceReference(value: string, label: string): void {
|
|
296
|
+
if (value.includes("\0")) {
|
|
297
|
+
throw invalidConfig(`${label} must not contain null bytes.`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (/^https?:\/\//i.test(value)) {
|
|
301
|
+
validateKnowledgeUrl(value, label);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function validateKnowledgeUrl(value: string, label: string): void {
|
|
306
|
+
let url: URL;
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
url = new URL(value);
|
|
310
|
+
} catch {
|
|
311
|
+
throw invalidConfig(`${label} must be a valid http or https URL.`);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
315
|
+
throw invalidConfig(`${label} must be a valid http or https URL.`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function validateKnowledgeEmbedding(value: unknown): void {
|
|
320
|
+
if (!isRecord(value)) {
|
|
321
|
+
throw invalidConfig("knowledge.embedding must be an object when provided.");
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (value.provider !== undefined && !KNOWLEDGE_EMBEDDING_PROVIDERS.has(value.provider as AgentKnowledgeEmbeddingProvider)) {
|
|
325
|
+
throw invalidConfig(
|
|
326
|
+
`knowledge.embedding.provider must be one of: ${Array.from(KNOWLEDGE_EMBEDDING_PROVIDERS).join(", ")}.`,
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (value.model !== undefined) {
|
|
331
|
+
expectString(value.model, "knowledge.embedding.model");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (value.secret !== undefined) {
|
|
335
|
+
expectString(value.secret, "knowledge.embedding.secret");
|
|
336
|
+
validateSecretNames([value.secret], "knowledge.embedding.secret");
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const dimensions = value.dimensions;
|
|
340
|
+
if (dimensions !== undefined) {
|
|
341
|
+
if (typeof dimensions !== "number" || !Number.isInteger(dimensions) || dimensions <= 0 || dimensions > 65_536) {
|
|
342
|
+
throw invalidConfig("knowledge.embedding.dimensions must be a positive integer no larger than 65536.");
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function validateKnowledgeRetrieval(value: unknown): void {
|
|
348
|
+
if (!isRecord(value)) {
|
|
349
|
+
throw invalidConfig("knowledge.retrieval must be an object when provided.");
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const topK = value.topK;
|
|
353
|
+
if (topK !== undefined && (typeof topK !== "number" || !Number.isInteger(topK) || topK <= 0 || topK > 50)) {
|
|
354
|
+
throw invalidConfig("knowledge.retrieval.topK must be a positive integer no larger than 50.");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (value.hybrid !== undefined && typeof value.hybrid !== "boolean") {
|
|
358
|
+
throw invalidConfig("knowledge.retrieval.hybrid must be a boolean when provided.");
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
229
362
|
function validateChannels(value: unknown, runtime: AgentRuntime): void {
|
|
230
363
|
if (value === undefined) {
|
|
231
364
|
return;
|
|
@@ -276,6 +409,7 @@ function validateChannel(value: unknown, index: number): asserts value is AgentC
|
|
|
276
409
|
expectStringArray(value.secrets, `channels[${index}].secrets`);
|
|
277
410
|
validateSecretNames(value.secrets, `channels[${index}].secrets`);
|
|
278
411
|
validateChannelLimits(value.limits, index);
|
|
412
|
+
validateChannelBuffer(value.buffer, index);
|
|
279
413
|
|
|
280
414
|
if (value.type === "website") {
|
|
281
415
|
validateWebsiteChannel(value, index);
|
|
@@ -361,6 +495,39 @@ function validateChannelLimits(value: unknown, index: number): void {
|
|
|
361
495
|
}
|
|
362
496
|
}
|
|
363
497
|
|
|
498
|
+
function validateChannelBuffer(value: unknown, index: number): void {
|
|
499
|
+
if (value === undefined) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (!isRecord(value)) {
|
|
504
|
+
throw invalidConfig(`channels[${index}].buffer must be an object when provided.`);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (!CHANNEL_BUFFER_MODES.has(value.mode as ChannelBufferMode)) {
|
|
508
|
+
throw invalidConfig(`channels[${index}].buffer.mode must be "off" or "debounce".`);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (value.mode === "off") {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
for (const field of ["quietWindowMs", "maxWaitMs", "maxMessages", "maxChars"] as const) {
|
|
516
|
+
if (
|
|
517
|
+
value[field] === undefined ||
|
|
518
|
+
typeof value[field] !== "number" ||
|
|
519
|
+
!Number.isInteger(value[field]) ||
|
|
520
|
+
value[field] <= 0
|
|
521
|
+
) {
|
|
522
|
+
throw invalidConfig(`channels[${index}].buffer.${field} must be a positive integer.`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if ((value.maxWaitMs as number) < (value.quietWindowMs as number)) {
|
|
527
|
+
throw invalidConfig(`channels[${index}].buffer.maxWaitMs must be greater than or equal to quietWindowMs.`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
364
531
|
function validateSecretNames(secrets: string[], field: string): void {
|
|
365
532
|
for (const secret of secrets) {
|
|
366
533
|
if (!SECRET_NAME_PATTERN.test(secret)) {
|
|
@@ -394,6 +561,10 @@ function validateDatabaseConfig(value: unknown): void {
|
|
|
394
561
|
if (value.schema !== undefined && typeof value.schema !== "string") {
|
|
395
562
|
throw invalidConfig("storage.database.schema must be a string when provided.");
|
|
396
563
|
}
|
|
564
|
+
|
|
565
|
+
if (value.migrations !== undefined && typeof value.migrations !== "string") {
|
|
566
|
+
throw invalidConfig("storage.database.migrations must be a string when provided.");
|
|
567
|
+
}
|
|
397
568
|
}
|
|
398
569
|
|
|
399
570
|
function validateFilesConfig(value: unknown): void {
|
|
@@ -464,6 +635,10 @@ function validateTool(value: unknown, index: number): asserts value is AgentTool
|
|
|
464
635
|
if (typeof value.execute !== "function") {
|
|
465
636
|
throw invalidConfig(`tools[${index}].execute must be a function.`);
|
|
466
637
|
}
|
|
638
|
+
|
|
639
|
+
if (value.render !== undefined && typeof value.render !== "function") {
|
|
640
|
+
throw invalidConfig(`tools[${index}].render must be a function when provided.`);
|
|
641
|
+
}
|
|
467
642
|
}
|
|
468
643
|
|
|
469
644
|
function resolvePath(root: string, path: string): string {
|
|
@@ -2,6 +2,8 @@ import { relative, resolve } from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import type { AgentConfig, AgentTool } from "../../index";
|
|
4
4
|
import type { LoadedAgentCapsule } from "../config";
|
|
5
|
+
import { resolveKnowledgeConfig } from "../knowledge/config";
|
|
6
|
+
import { KNOWLEDGE_SEARCH_TOOL_NAME } from "../knowledge/tool";
|
|
5
7
|
|
|
6
8
|
export type ManifestSchema = {
|
|
7
9
|
source: string;
|
|
@@ -25,6 +27,25 @@ export type SharedAgentManifest = {
|
|
|
25
27
|
timeoutMs: number | null;
|
|
26
28
|
}>;
|
|
27
29
|
channels: NonNullable<AgentConfig["channels"]>;
|
|
30
|
+
knowledge: {
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
sources: Array<{
|
|
33
|
+
kind: "file" | "url";
|
|
34
|
+
value: string;
|
|
35
|
+
title: string | null;
|
|
36
|
+
}>;
|
|
37
|
+
embedding: {
|
|
38
|
+
provider: string;
|
|
39
|
+
model: string | null;
|
|
40
|
+
dimensions: number | null;
|
|
41
|
+
secret: string | null;
|
|
42
|
+
};
|
|
43
|
+
retrieval: {
|
|
44
|
+
topK: number;
|
|
45
|
+
hybrid: boolean;
|
|
46
|
+
};
|
|
47
|
+
internalTool: string | null;
|
|
48
|
+
};
|
|
28
49
|
access: AgentConfig["access"];
|
|
29
50
|
storage: {
|
|
30
51
|
driver: AgentConfig["storage"]["driver"];
|
|
@@ -57,6 +78,7 @@ export function buildSharedAgentManifest(
|
|
|
57
78
|
const requiredSecrets = new Set(capsule.config.secrets);
|
|
58
79
|
const database = buildDatabaseManifest(capsule, options.databaseSchema ?? null);
|
|
59
80
|
const files = buildFilesManifest(capsule);
|
|
81
|
+
const knowledge = resolveKnowledgeConfig(capsule.config);
|
|
60
82
|
|
|
61
83
|
if (capsule.config.access.mode === "private") {
|
|
62
84
|
requiredSecrets.add("AGENTKIT_PRIVATE_TOKEN");
|
|
@@ -75,6 +97,10 @@ export function buildSharedAgentManifest(
|
|
|
75
97
|
requiredSecrets.add("TURSO_AUTH_TOKEN");
|
|
76
98
|
}
|
|
77
99
|
|
|
100
|
+
if (knowledge.embedding.secret) {
|
|
101
|
+
requiredSecrets.add(knowledge.embedding.secret);
|
|
102
|
+
}
|
|
103
|
+
|
|
78
104
|
for (const tool of capsule.config.tools ?? []) {
|
|
79
105
|
for (const secret of tool.secrets ?? []) {
|
|
80
106
|
requiredSecrets.add(secret);
|
|
@@ -104,6 +130,17 @@ export function buildSharedAgentManifest(
|
|
|
104
130
|
timeoutMs: tool.timeoutMs ?? null,
|
|
105
131
|
})),
|
|
106
132
|
channels: capsule.config.channels ?? [],
|
|
133
|
+
knowledge: {
|
|
134
|
+
enabled: knowledge.enabled,
|
|
135
|
+
sources: knowledge.sources.map((source) => ({
|
|
136
|
+
kind: source.kind,
|
|
137
|
+
value: source.value,
|
|
138
|
+
title: source.title,
|
|
139
|
+
})),
|
|
140
|
+
embedding: knowledge.embedding,
|
|
141
|
+
retrieval: knowledge.retrieval,
|
|
142
|
+
internalTool: knowledge.enabled ? KNOWLEDGE_SEARCH_TOOL_NAME : null,
|
|
143
|
+
},
|
|
107
144
|
access: capsule.config.access,
|
|
108
145
|
storage: {
|
|
109
146
|
driver: capsule.config.storage.driver,
|