@andreprado/agentkit 0.1.0-alpha.2 → 0.1.0-alpha.20

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.
Files changed (135) hide show
  1. package/README.md +67 -6
  2. package/docs/guides/add-channel.md +118 -7
  3. package/docs/guides/add-knowledge.md +144 -0
  4. package/docs/guides/add-managed-composio.md +163 -0
  5. package/docs/guides/add-tool.md +1 -1
  6. package/docs/guides/channel-security.md +97 -32
  7. package/docs/guides/connect-discord.md +178 -0
  8. package/docs/guides/connect-slack.md +126 -0
  9. package/docs/guides/connect-telegram.md +78 -1
  10. package/docs/guides/connect-whatsapp-zapster.md +112 -8
  11. package/docs/guides/create-agent.md +45 -4
  12. package/docs/guides/debug-channel.md +147 -0
  13. package/docs/guides/improve-from-production.md +151 -0
  14. package/docs/guides/prepare-deploy.md +47 -17
  15. package/docs/guides/replay-production-traces.md +72 -0
  16. package/docs/guides/run-evals.md +147 -20
  17. package/docs/guides/security-rules.md +7 -6
  18. package/docs/guides/send-feedback.md +135 -0
  19. package/docs/guides/use-provider.md +27 -3
  20. package/docs/llms-full.txt +303 -55
  21. package/docs/llms.txt +57 -7
  22. package/package.json +2 -5
  23. package/src/cli/args.ts +57 -0
  24. package/src/cli/cloud-client.ts +377 -0
  25. package/src/cli/commands/channels.ts +1315 -0
  26. package/src/cli/commands/feedback.ts +438 -0
  27. package/src/cli/commands/knowledge.ts +136 -0
  28. package/src/cli/commands/transcribe.ts +171 -0
  29. package/src/cli/constants.ts +4 -0
  30. package/src/cli/deploy-chat-ui.ts +535 -0
  31. package/src/cli/deploy-readiness.ts +481 -0
  32. package/src/cli/flags.ts +162 -0
  33. package/src/cli/help.ts +236 -0
  34. package/src/cli/index.ts +1167 -1005
  35. package/src/cli/process.ts +31 -0
  36. package/src/cloud/artifact.ts +139 -0
  37. package/src/cloud/client.ts +80 -0
  38. package/src/cloud/contracts.ts +63 -0
  39. package/src/cloud/index.ts +3 -0
  40. package/src/create-project.ts +21 -6
  41. package/src/index.ts +479 -7
  42. package/src/providers/pi.ts +70 -16
  43. package/src/providers/test.ts +88 -1
  44. package/src/providers/types.ts +7 -0
  45. package/src/runtime/channel-buffer.ts +30 -0
  46. package/src/runtime/channel-test-harness.ts +8 -1
  47. package/src/runtime/channels/discord.ts +896 -0
  48. package/src/runtime/channels/slack.ts +646 -0
  49. package/src/runtime/channels/telegram.ts +466 -23
  50. package/src/runtime/channels/whatsapp-meta.ts +9 -0
  51. package/src/runtime/channels/whatsapp-zapster.ts +677 -40
  52. package/src/runtime/channels.ts +86 -3
  53. package/src/runtime/chat.ts +130 -38
  54. package/src/runtime/config.ts +483 -18
  55. package/src/runtime/core/manifest.ts +103 -5
  56. package/src/runtime/core/targets.ts +5 -5
  57. package/src/runtime/database.ts +93 -2
  58. package/src/runtime/db-commands.ts +9 -0
  59. package/src/runtime/deploy-readiness.ts +46 -4
  60. package/src/runtime/deploy.ts +1 -1
  61. package/src/runtime/dev-server.ts +759 -41
  62. package/src/runtime/env.ts +8 -3
  63. package/src/runtime/evals.ts +589 -43
  64. package/src/runtime/improve.ts +868 -0
  65. package/src/runtime/inspect.ts +194 -4
  66. package/src/runtime/integrations/composio.ts +423 -0
  67. package/src/runtime/knowledge/chunk.ts +333 -0
  68. package/src/runtime/knowledge/config.ts +135 -0
  69. package/src/runtime/knowledge/embeddings.ts +133 -0
  70. package/src/runtime/knowledge/ingest.ts +521 -0
  71. package/src/runtime/knowledge/prompt-policy.ts +30 -0
  72. package/src/runtime/knowledge/retrieve.ts +303 -0
  73. package/src/runtime/knowledge/schema.ts +100 -0
  74. package/src/runtime/knowledge/tool.ts +64 -0
  75. package/src/runtime/knowledge/vector.ts +258 -0
  76. package/src/runtime/prompt-context.ts +141 -0
  77. package/src/runtime/runtime-contract.ts +86 -8
  78. package/src/runtime/skills.ts +95 -0
  79. package/src/runtime/spec.ts +152 -0
  80. package/src/runtime/sync.ts +144 -0
  81. package/src/runtime/targets/cloudflare/build.ts +1430 -185
  82. package/src/runtime/targets/container/server.ts +1 -1
  83. package/src/runtime/targets/vps/deploy.ts +26 -9
  84. package/src/runtime/tool-runner.ts +9 -1
  85. package/src/runtime/tools.ts +128 -2
  86. package/src/runtime/traces.ts +41 -0
  87. package/src/runtime/transcription.ts +483 -0
  88. package/src/storage/sqlite.ts +149 -3
  89. package/src/templates/blank.ts +76 -17
  90. package/src/templates/dentista.ts +1011 -0
  91. package/src/templates/index.ts +2 -0
  92. package/src/templates/skills/agentkit-build-agent/SKILL.md +52 -0
  93. package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md +21 -0
  94. package/src/templates/skills/agentkit-build-agent/templates/sales-qualifier.instructions.md +17 -0
  95. package/src/templates/skills/agentkit-build-agent/templates/support-agent.instructions.md +16 -0
  96. package/src/templates/skills/agentkit-capsule/SKILL.md +70 -0
  97. package/src/templates/skills/agentkit-capsule/references/docs-router.md +15 -0
  98. package/src/templates/skills/agentkit-channels/SKILL.md +104 -0
  99. package/src/templates/skills/agentkit-channels/references/channel-buffering.md +65 -0
  100. package/src/templates/skills/agentkit-channels/references/channel-debugging.md +66 -0
  101. package/src/templates/skills/agentkit-channels/references/discord.md +93 -0
  102. package/src/templates/skills/agentkit-channels/references/slack.md +56 -0
  103. package/src/templates/skills/agentkit-channels/references/telegram.md +72 -0
  104. package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +77 -0
  105. package/src/templates/skills/agentkit-database/SKILL.md +45 -0
  106. package/src/templates/skills/agentkit-database/templates/appointments.schema.sql +15 -0
  107. package/src/templates/skills/agentkit-database/templates/leads.schema.sql +17 -0
  108. package/src/templates/skills/agentkit-deploy/SKILL.md +50 -0
  109. package/src/templates/skills/agentkit-evals/SKILL.md +109 -0
  110. package/src/templates/skills/agentkit-evals/templates/multi-turn.eval.md +29 -0
  111. package/src/templates/skills/agentkit-evals/templates/no-leak.eval.md +18 -0
  112. package/src/templates/skills/agentkit-evals/templates/smoke.eval.md +18 -0
  113. package/src/templates/skills/agentkit-evals/templates/tool-call.eval.md +27 -0
  114. package/src/templates/skills/agentkit-improve/SKILL.md +86 -0
  115. package/src/templates/skills/agentkit-improve/references/replay-side-effects.md +18 -0
  116. package/src/templates/skills/agentkit-improve/references/trace-packets.md +22 -0
  117. package/src/templates/skills/agentkit-improve/templates/regression.eval.md +18 -0
  118. package/src/templates/skills/agentkit-integrations/SKILL.md +76 -0
  119. package/src/templates/skills/agentkit-knowledge/SKILL.md +43 -0
  120. package/src/templates/skills/agentkit-knowledge/templates/faq.md +14 -0
  121. package/src/templates/skills/agentkit-knowledge/templates/policies.md +14 -0
  122. package/src/templates/skills/agentkit-knowledge/templates/prices.csv +3 -0
  123. package/src/templates/skills/agentkit-prompts/SKILL.md +47 -0
  124. package/src/templates/skills/agentkit-prompts/templates/knowledge-grounded-faq.instructions.md +11 -0
  125. package/src/templates/skills/agentkit-provider/SKILL.md +60 -0
  126. package/src/templates/skills/agentkit-security/SKILL.md +56 -0
  127. package/src/templates/skills/agentkit-tools/SKILL.md +37 -0
  128. package/src/templates/skills/agentkit-tools/examples/database-write.tool.md +35 -0
  129. package/src/templates/skills/agentkit-tools/examples/eval-safe-external-action.tool.md +37 -0
  130. package/src/templates/skills/agentkit-tools/examples/lookup-order.tool.md +46 -0
  131. package/src/templates/skills/agentkit-troubleshooting/SKILL.md +76 -0
  132. package/src/templates/support.ts +77 -18
  133. package/docs/guides/channels-production-handoff.md +0 -99
  134. package/docs/portable-deploy-release-checklist.md +0 -41
  135. package/src/runtime/targets/cloudflare/deploy.ts +0 -5475
@@ -0,0 +1,303 @@
1
+ import type { DatabaseRunner, DatabaseRow } from "../../index";
2
+ import { createLocalDatabaseRunner, openPreparedCapsuleStore } from "../database";
3
+ import { loadCapsuleEnv } from "../env";
4
+ import { AgentKitError } from "../errors";
5
+ import { loadAgentCapsule, type LoadedAgentCapsule } from "../config";
6
+ import { resolveKnowledgeConfig } from "./config";
7
+ import { cosineSimilarity, createEmbeddingProvider } from "./embeddings";
8
+ import { searchLocalKnowledgeVectorRows } from "./vector";
9
+
10
+ export type KnowledgeSearchResult = {
11
+ chunkId: string;
12
+ content: string;
13
+ score: number;
14
+ source: {
15
+ id: string;
16
+ path: string;
17
+ title: string | null;
18
+ section: string | null;
19
+ locator: string | null;
20
+ };
21
+ match: {
22
+ lexical: number;
23
+ semantic: number | null;
24
+ };
25
+ };
26
+
27
+ export async function searchKnowledgeFromCwd(
28
+ cwd: string,
29
+ query: string,
30
+ options: { topK?: number } = {},
31
+ ): Promise<{ databasePath: string; results: KnowledgeSearchResult[] }> {
32
+ const capsule = await loadAgentCapsule(cwd);
33
+ const { store, databasePath } = await openPreparedCapsuleStore(capsule);
34
+
35
+ try {
36
+ const db = createLocalDatabaseRunner(store);
37
+ return {
38
+ databasePath,
39
+ results: await searchKnowledge(capsule, db, query, options),
40
+ };
41
+ } finally {
42
+ store.close();
43
+ }
44
+ }
45
+
46
+ export async function searchKnowledge(
47
+ capsule: LoadedAgentCapsule,
48
+ db: DatabaseRunner,
49
+ query: string,
50
+ options: { topK?: number } = {},
51
+ ): Promise<KnowledgeSearchResult[]> {
52
+ const normalizedQuery = query.trim();
53
+
54
+ if (!normalizedQuery) {
55
+ throw new AgentKitError("knowledge_query_invalid", "Knowledge search query must be a non-empty string.");
56
+ }
57
+
58
+ const knowledge = resolveKnowledgeConfig(capsule.config);
59
+ const topK = options.topK ?? knowledge.retrieval.topK;
60
+ const env = await loadCapsuleEnv(capsule.root);
61
+ const embeddingProvider = createEmbeddingProvider({
62
+ config: knowledge.embedding,
63
+ env,
64
+ });
65
+ const lexical = knowledge.retrieval.hybrid || !embeddingProvider
66
+ ? await searchLexical(db, normalizedQuery, Math.max(topK * 4, topK))
67
+ : [];
68
+ const semantic = embeddingProvider
69
+ ? await searchSemantic(capsule, db, normalizedQuery, topK * 4, embeddingProvider)
70
+ : [];
71
+
72
+ return combineResults(lexical, semantic, topK);
73
+ }
74
+
75
+ async function searchLexical(db: DatabaseRunner, query: string, limit: number): Promise<KnowledgeSearchResult[]> {
76
+ const tokens = queryTokens(query);
77
+
78
+ if (tokens.length === 0) {
79
+ return [];
80
+ }
81
+
82
+ try {
83
+ const result = await db.query(
84
+ `
85
+ SELECT
86
+ c.id AS chunk_id,
87
+ c.source_id AS source_id,
88
+ c.content AS content,
89
+ c.title AS title,
90
+ c.section AS section,
91
+ c.locator AS locator,
92
+ s.source_key AS source_key,
93
+ rank
94
+ FROM agentkit_knowledge_fts
95
+ JOIN agentkit_knowledge_chunks c ON c.id = agentkit_knowledge_fts.chunk_id
96
+ JOIN agentkit_knowledge_sources s ON s.id = c.source_id
97
+ WHERE agentkit_knowledge_fts MATCH ?
98
+ ORDER BY rank ASC
99
+ LIMIT ?
100
+ `,
101
+ [tokens.map((token) => `"${token.replace(/"/g, '""')}"`).join(" OR "), limit],
102
+ );
103
+
104
+ return result.rows.map((row, index) => knowledgeSearchResultFromRow(row, lexicalScore(index), null));
105
+ } catch {
106
+ return searchLexicalFallback(db, query, limit);
107
+ }
108
+ }
109
+
110
+ async function searchLexicalFallback(db: DatabaseRunner, query: string, limit: number): Promise<KnowledgeSearchResult[]> {
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
+ });
130
+ const result = await db.query(
131
+ `
132
+ SELECT
133
+ c.id AS chunk_id,
134
+ c.source_id AS source_id,
135
+ c.content AS content,
136
+ c.title AS title,
137
+ c.section AS section,
138
+ c.locator AS locator,
139
+ s.source_key AS source_key
140
+ FROM agentkit_knowledge_chunks c
141
+ JOIN agentkit_knowledge_sources s ON s.id = c.source_id
142
+ WHERE ${conditions}
143
+ ORDER BY c.created_at DESC, c.ordinal ASC
144
+ LIMIT ?
145
+ `,
146
+ [...args, limit],
147
+ );
148
+
149
+ return result.rows.map((row, index) => knowledgeSearchResultFromRow(row, lexicalScore(index), null));
150
+ }
151
+
152
+ async function searchSemantic(
153
+ capsule: LoadedAgentCapsule,
154
+ db: DatabaseRunner,
155
+ query: string,
156
+ limit: number,
157
+ embeddingProvider: NonNullable<ReturnType<typeof createEmbeddingProvider>>,
158
+ ): Promise<KnowledgeSearchResult[]> {
159
+ const queryEmbedding = await embeddingProvider.embed(query);
160
+
161
+ if (capsule.storagePath) {
162
+ try {
163
+ const vectorRows = await searchLocalKnowledgeVectorRows({
164
+ databasePath: capsule.storagePath,
165
+ queryEmbedding,
166
+ limit,
167
+ });
168
+
169
+ return vectorRows
170
+ .map((row) => {
171
+ const distance = Number(row.vector_distance);
172
+ const semantic = Number.isFinite(distance) ? 1 - distance : 0;
173
+ return knowledgeSearchResultFromRow(row, 0, semantic);
174
+ })
175
+ .filter((result) => result.match.semantic !== null && result.match.semantic > 0)
176
+ .slice(0, limit);
177
+ } catch {
178
+ // Older local databases and non-libSQL environments use the JSON fallback below.
179
+ }
180
+ }
181
+
182
+ const result = await db.query(
183
+ `
184
+ SELECT
185
+ c.id AS chunk_id,
186
+ c.source_id AS source_id,
187
+ c.content AS content,
188
+ c.title AS title,
189
+ c.section AS section,
190
+ c.locator AS locator,
191
+ c.embedding_json AS embedding_json,
192
+ s.source_key AS source_key
193
+ FROM agentkit_knowledge_chunks c
194
+ JOIN agentkit_knowledge_sources s ON s.id = c.source_id
195
+ WHERE c.embedding_json IS NOT NULL
196
+ ORDER BY c.created_at DESC, c.ordinal ASC
197
+ `,
198
+ );
199
+
200
+ return result.rows
201
+ .map((row) => {
202
+ const embedding = parseEmbedding(row.embedding_json);
203
+ const semantic = embedding ? cosineSimilarity(queryEmbedding, embedding) : 0;
204
+ return knowledgeSearchResultFromRow(row, 0, semantic);
205
+ })
206
+ .filter((result) => result.match.semantic !== null && result.match.semantic > 0)
207
+ .sort((left, right) => (right.match.semantic ?? 0) - (left.match.semantic ?? 0))
208
+ .slice(0, limit);
209
+ }
210
+
211
+ function combineResults(
212
+ lexical: KnowledgeSearchResult[],
213
+ semantic: KnowledgeSearchResult[],
214
+ topK: number,
215
+ ): KnowledgeSearchResult[] {
216
+ const byChunk = new Map<string, KnowledgeSearchResult>();
217
+
218
+ for (const result of lexical) {
219
+ byChunk.set(result.chunkId, result);
220
+ }
221
+
222
+ for (const result of semantic) {
223
+ const existing = byChunk.get(result.chunkId);
224
+
225
+ if (!existing) {
226
+ byChunk.set(result.chunkId, {
227
+ ...result,
228
+ score: combinedScore(0, result.match.semantic),
229
+ });
230
+ continue;
231
+ }
232
+
233
+ byChunk.set(result.chunkId, {
234
+ ...existing,
235
+ score: combinedScore(existing.match.lexical, result.match.semantic),
236
+ match: {
237
+ lexical: existing.match.lexical,
238
+ semantic: result.match.semantic,
239
+ },
240
+ });
241
+ }
242
+
243
+ return Array.from(byChunk.values())
244
+ .map((result) => ({
245
+ ...result,
246
+ score: result.score || combinedScore(result.match.lexical, result.match.semantic),
247
+ }))
248
+ .sort((left, right) => right.score - left.score || left.source.path.localeCompare(right.source.path))
249
+ .slice(0, topK);
250
+ }
251
+
252
+ function knowledgeSearchResultFromRow(
253
+ row: DatabaseRow,
254
+ lexical: number,
255
+ semantic: number | null,
256
+ ): KnowledgeSearchResult {
257
+ return {
258
+ chunkId: String(row.chunk_id),
259
+ content: String(row.content),
260
+ score: combinedScore(lexical, semantic),
261
+ source: {
262
+ id: String(row.source_id),
263
+ path: String(row.source_key),
264
+ title: typeof row.title === "string" ? row.title : null,
265
+ section: typeof row.section === "string" ? row.section : null,
266
+ locator: typeof row.locator === "string" ? row.locator : null,
267
+ },
268
+ match: {
269
+ lexical,
270
+ semantic,
271
+ },
272
+ };
273
+ }
274
+
275
+ function combinedScore(lexical: number, semantic: number | null): number {
276
+ const semanticScore = semantic === null ? 0 : Math.max(0, (semantic + 1) / 2);
277
+ return Number((lexical * 0.6 + semanticScore * 0.4).toFixed(6));
278
+ }
279
+
280
+ function lexicalScore(index: number): number {
281
+ return Number((1 / (index + 1)).toFixed(6));
282
+ }
283
+
284
+ function queryTokens(query: string): string[] {
285
+ return Array.from(new Set(query.toLowerCase().match(/[\p{L}\p{N}_-]+/gu) ?? [])).slice(0, 12);
286
+ }
287
+
288
+ function likePattern(token: string): string {
289
+ return `%${token.replace(/[\\%_]/g, (value) => `\\${value}`)}%`;
290
+ }
291
+
292
+ function parseEmbedding(value: unknown): number[] | null {
293
+ if (typeof value !== "string") {
294
+ return null;
295
+ }
296
+
297
+ try {
298
+ const parsed = JSON.parse(value);
299
+ return Array.isArray(parsed) && parsed.every((item) => typeof item === "number") ? parsed : null;
300
+ } catch {
301
+ return null;
302
+ }
303
+ }
@@ -0,0 +1,100 @@
1
+ export const KNOWLEDGE_MIGRATION_ID = "0006_create_knowledge_tables";
2
+
3
+ type KnowledgeSchemaDatabase = {
4
+ exec(sql: string): unknown;
5
+ };
6
+
7
+ export type KnowledgeLexicalIndexMode = "fts5" | "fallback";
8
+
9
+ export const KNOWLEDGE_BASE_SCHEMA_SQL = `
10
+ CREATE TABLE IF NOT EXISTS agentkit_knowledge_sources (
11
+ id TEXT PRIMARY KEY,
12
+ source_key TEXT NOT NULL UNIQUE,
13
+ kind TEXT NOT NULL,
14
+ path TEXT,
15
+ url TEXT,
16
+ title TEXT,
17
+ content_sha256 TEXT,
18
+ status TEXT NOT NULL DEFAULT 'pending',
19
+ chunk_count INTEGER NOT NULL DEFAULT 0,
20
+ metadata_json TEXT NOT NULL DEFAULT '{}',
21
+ created_at TEXT NOT NULL,
22
+ updated_at TEXT NOT NULL,
23
+ indexed_at TEXT,
24
+ error_message TEXT
25
+ );
26
+
27
+ CREATE INDEX IF NOT EXISTS agentkit_knowledge_sources_status_idx
28
+ ON agentkit_knowledge_sources(status, updated_at);
29
+
30
+ CREATE TABLE IF NOT EXISTS agentkit_knowledge_chunks (
31
+ id TEXT PRIMARY KEY,
32
+ source_id TEXT NOT NULL REFERENCES agentkit_knowledge_sources(id) ON DELETE CASCADE,
33
+ ordinal INTEGER NOT NULL,
34
+ content TEXT NOT NULL,
35
+ token_count INTEGER NOT NULL,
36
+ title TEXT,
37
+ section TEXT,
38
+ locator TEXT,
39
+ content_sha256 TEXT NOT NULL,
40
+ embedding_json TEXT,
41
+ embedding_hash TEXT,
42
+ embedding_provider TEXT,
43
+ embedding_model TEXT,
44
+ embedding_dimensions INTEGER,
45
+ metadata_json TEXT NOT NULL DEFAULT '{}',
46
+ created_at TEXT NOT NULL,
47
+ UNIQUE(source_id, ordinal)
48
+ );
49
+
50
+ CREATE INDEX IF NOT EXISTS agentkit_knowledge_chunks_source_ordinal_idx
51
+ ON agentkit_knowledge_chunks(source_id, ordinal);
52
+ `;
53
+
54
+ export const KNOWLEDGE_FTS5_SCHEMA_SQL = `
55
+ CREATE VIRTUAL TABLE IF NOT EXISTS agentkit_knowledge_fts
56
+ USING fts5(
57
+ chunk_id UNINDEXED,
58
+ source_id UNINDEXED,
59
+ title,
60
+ section,
61
+ content,
62
+ tokenize='unicode61'
63
+ );
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
+ }
@@ -0,0 +1,64 @@
1
+ import type { AgentTool } from "../../index";
2
+ import type { LoadedAgentCapsule } from "../config";
3
+ import { resolveKnowledgeConfig } from "./config";
4
+ import { searchKnowledge } from "./retrieve";
5
+
6
+ export const KNOWLEDGE_SEARCH_TOOL_NAME = "agentkit_search_knowledge";
7
+
8
+ export function createKnowledgeSearchTool(capsule: LoadedAgentCapsule): AgentTool | null {
9
+ const knowledge = resolveKnowledgeConfig(capsule.config);
10
+
11
+ if (!knowledge.enabled) {
12
+ return null;
13
+ }
14
+
15
+ return {
16
+ name: KNOWLEDGE_SEARCH_TOOL_NAME,
17
+ description: "Search the Agent Capsule's configured Knowledge sources for business-specific facts.",
18
+ visibility: "internal",
19
+ inputSchema: {
20
+ type: "object",
21
+ properties: {
22
+ query: {
23
+ type: "string",
24
+ },
25
+ topK: {
26
+ type: "integer",
27
+ },
28
+ },
29
+ required: ["query"],
30
+ additionalProperties: false,
31
+ },
32
+ outputSchema: {
33
+ type: "object",
34
+ properties: {
35
+ results: {
36
+ type: "array",
37
+ items: {
38
+ type: "object",
39
+ properties: {
40
+ content: { type: "string" },
41
+ score: { type: "number" },
42
+ source: { type: "object" },
43
+ },
44
+ required: ["content", "score", "source"],
45
+ },
46
+ },
47
+ },
48
+ required: ["results"],
49
+ additionalProperties: false,
50
+ },
51
+ async execute(input, ctx) {
52
+ const typed = input as { query: string; topK?: number };
53
+ const results = await searchKnowledge(capsule, ctx.db, typed.query, { topK: typed.topK });
54
+
55
+ return {
56
+ results: results.map((result) => ({
57
+ content: result.content,
58
+ score: result.score,
59
+ source: result.source,
60
+ })),
61
+ };
62
+ },
63
+ };
64
+ }