@andreprado/agentkit 0.1.0-alpha.4 → 0.1.0-alpha.6
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 +5 -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 +15 -0
- package/docs/guides/connect-whatsapp-zapster.md +16 -0
- package/docs/guides/create-agent.md +1 -1
- package/docs/llms-full.txt +90 -1
- package/docs/llms.txt +9 -2
- package/package.json +2 -1
- package/src/cli/args.ts +36 -0
- package/src/cli/cloud-client.ts +257 -0
- package/src/cli/commands/channels.ts +459 -0
- package/src/cli/commands/knowledge.ts +136 -0
- package/src/cli/constants.ts +4 -0
- package/src/cli/deploy-chat-ui.ts +385 -0
- package/src/cli/deploy-readiness.ts +348 -0
- package/src/cli/flags.ts +162 -0
- package/src/cli/help.ts +166 -0
- package/src/cli/index.ts +219 -1912
- package/src/cli/process.ts +31 -0
- 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 +98 -0
- 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 +167 -0
- package/src/runtime/core/manifest.ts +37 -0
- package/src/runtime/deploy-readiness.ts +12 -0
- package/src/runtime/dev-server.ts +159 -10
- package/src/runtime/inspect.ts +34 -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/targets/cloudflare/build.ts +469 -4
- package/src/storage/sqlite.ts +5 -0
- package/src/templates/blank.ts +8 -4
- package/src/templates/dentista.ts +3 -1
- package/src/templates/skills/agentkit-build-agent/SKILL.md +49 -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 +42 -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 +31 -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 +8 -4
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
export function runInheritedCommand(command: string, args: string[], cwd: string): Promise<number> {
|
|
4
|
+
return new Promise((resolvePromise, reject) => {
|
|
5
|
+
const child = spawn(command, args, {
|
|
6
|
+
cwd,
|
|
7
|
+
stdio: "inherit",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
child.once("error", reject);
|
|
11
|
+
child.once("close", (code) => resolvePromise(code ?? 1));
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function waitForShutdown(stop: () => Promise<void>): Promise<void> {
|
|
16
|
+
await new Promise<void>((resolve) => {
|
|
17
|
+
let stopped = false;
|
|
18
|
+
|
|
19
|
+
const shutdown = () => {
|
|
20
|
+
if (stopped) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
stopped = true;
|
|
25
|
+
void stop().finally(resolve);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
process.once("SIGINT", shutdown);
|
|
29
|
+
process.once("SIGTERM", shutdown);
|
|
30
|
+
});
|
|
31
|
+
}
|
package/src/cloud/artifact.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { extname, isAbsolute, relative, resolve } from "node:path";
|
|
3
4
|
|
|
4
5
|
import type { AgentBuildResult, AgentManifestWithBundle } from "../runtime/targets/cloudflare/build";
|
|
5
6
|
import { AgentKitError } from "../runtime/errors";
|
|
6
7
|
import type { HostedDeployArtifact } from "./contracts";
|
|
7
8
|
|
|
9
|
+
const HOSTED_KNOWLEDGE_MAX_SOURCE_BYTES = 5 * 1024 * 1024;
|
|
10
|
+
const HOSTED_KNOWLEDGE_MAX_TOTAL_BYTES = 9 * 1024 * 1024;
|
|
11
|
+
const HOSTED_KNOWLEDGE_SUPPORTED_EXTENSIONS = new Set([".md", ".markdown", ".txt", ".csv"]);
|
|
12
|
+
|
|
8
13
|
export async function createHostedDeployArtifact(build: AgentBuildResult): Promise<HostedDeployArtifact> {
|
|
9
14
|
const [manifestSource, workerSource, wranglerSource] = await Promise.all([
|
|
10
15
|
readFile(build.manifestPath, "utf8"),
|
|
@@ -40,9 +45,95 @@ export async function createHostedDeployArtifact(build: AgentBuildResult): Promi
|
|
|
40
45
|
};
|
|
41
46
|
}
|
|
42
47
|
|
|
48
|
+
if (manifest.knowledge.enabled) {
|
|
49
|
+
artifact.knowledge_sources = await createHostedKnowledgeSources(build.root, manifest);
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
return artifact;
|
|
44
53
|
}
|
|
45
54
|
|
|
55
|
+
async function createHostedKnowledgeSources(
|
|
56
|
+
root: string,
|
|
57
|
+
manifest: AgentManifestWithBundle,
|
|
58
|
+
): Promise<NonNullable<HostedDeployArtifact["knowledge_sources"]>> {
|
|
59
|
+
const sources: NonNullable<HostedDeployArtifact["knowledge_sources"]>["sources"] = [];
|
|
60
|
+
let totalBytes = 0;
|
|
61
|
+
|
|
62
|
+
for (const source of manifest.knowledge.sources) {
|
|
63
|
+
if (source.kind === "url") {
|
|
64
|
+
throw new AgentKitError(
|
|
65
|
+
"artifact_knowledge_source_unsupported",
|
|
66
|
+
"Hosted deploy can automatically sync local Knowledge files only. URL Knowledge sources require a hosted ingestion connector.",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const absolutePath = resolve(root, source.value);
|
|
71
|
+
const sourceKey = capsuleRelativePath(root, absolutePath);
|
|
72
|
+
const extension = extname(sourceKey).toLowerCase();
|
|
73
|
+
|
|
74
|
+
if (!HOSTED_KNOWLEDGE_SUPPORTED_EXTENSIONS.has(extension)) {
|
|
75
|
+
throw new AgentKitError(
|
|
76
|
+
"artifact_knowledge_source_unsupported",
|
|
77
|
+
`Knowledge source "${sourceKey}" is not supported for hosted deploy. Use .md, .txt, or .csv.`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const stats = await stat(absolutePath).catch((error) => {
|
|
82
|
+
throw new AgentKitError("artifact_knowledge_source_missing", `Knowledge source "${sourceKey}" was not found.`, {
|
|
83
|
+
cause: error,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (!stats.isFile()) {
|
|
88
|
+
throw new AgentKitError("artifact_knowledge_source_invalid", `Knowledge source "${sourceKey}" must be a file.`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (stats.size > HOSTED_KNOWLEDGE_MAX_SOURCE_BYTES) {
|
|
92
|
+
throw new AgentKitError(
|
|
93
|
+
"artifact_knowledge_source_too_large",
|
|
94
|
+
`Knowledge source "${sourceKey}" is too large for automatic deploy sync. Keep each source under 5MB.`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
totalBytes += stats.size;
|
|
99
|
+
|
|
100
|
+
if (totalBytes > HOSTED_KNOWLEDGE_MAX_TOTAL_BYTES) {
|
|
101
|
+
throw new AgentKitError(
|
|
102
|
+
"artifact_knowledge_sources_too_large",
|
|
103
|
+
"Knowledge sources are too large for automatic deploy sync. Keep total packaged Knowledge under 9MB.",
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const content = await readFile(absolutePath, "utf8");
|
|
108
|
+
sources.push({
|
|
109
|
+
kind: "file",
|
|
110
|
+
source_key: sourceKey,
|
|
111
|
+
title: source.title,
|
|
112
|
+
content,
|
|
113
|
+
sha256: sha256(content),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
content_type: "application/json",
|
|
119
|
+
sources,
|
|
120
|
+
sha256: sha256(JSON.stringify(sources)),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function capsuleRelativePath(root: string, absolutePath: string): string {
|
|
125
|
+
const relativePath = relative(root, absolutePath);
|
|
126
|
+
|
|
127
|
+
if (!relativePath || relativePath.startsWith("..") || isAbsolute(relativePath)) {
|
|
128
|
+
throw new AgentKitError(
|
|
129
|
+
"artifact_knowledge_source_outside_capsule",
|
|
130
|
+
"Knowledge source paths must stay inside the Agent Capsule.",
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return relativePath.split("\\").join("/");
|
|
135
|
+
}
|
|
136
|
+
|
|
46
137
|
function sha256(source: string): string {
|
|
47
138
|
return createHash("sha256").update(source).digest("hex");
|
|
48
139
|
}
|
package/src/cloud/contracts.ts
CHANGED
|
@@ -16,6 +16,17 @@ export type HostedDeployArtifact = {
|
|
|
16
16
|
source: string;
|
|
17
17
|
sha256: string;
|
|
18
18
|
};
|
|
19
|
+
knowledge_sources?: {
|
|
20
|
+
content_type: "application/json";
|
|
21
|
+
sources: Array<{
|
|
22
|
+
kind: "file";
|
|
23
|
+
source_key: string;
|
|
24
|
+
title: string | null;
|
|
25
|
+
content: string;
|
|
26
|
+
sha256: string;
|
|
27
|
+
}>;
|
|
28
|
+
sha256: string;
|
|
29
|
+
};
|
|
19
30
|
};
|
|
20
31
|
|
|
21
32
|
export type CreateDeployRequest = {
|
|
@@ -37,6 +48,11 @@ export type CreateDeployResponse = {
|
|
|
37
48
|
mode: string;
|
|
38
49
|
private_token?: string;
|
|
39
50
|
};
|
|
51
|
+
knowledge?: {
|
|
52
|
+
enabled: boolean;
|
|
53
|
+
sources: number;
|
|
54
|
+
chunks: number;
|
|
55
|
+
};
|
|
40
56
|
};
|
|
41
57
|
};
|
|
42
58
|
|
package/src/create-project.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
-
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
2
|
+
import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
|
-
import { getTemplate } from "./templates";
|
|
7
|
+
import { getTemplate, type TemplateFile } from "./templates";
|
|
8
8
|
|
|
9
9
|
const execFileAsync = promisify(execFile);
|
|
10
10
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -27,9 +27,12 @@ export async function createProject(options: CreateProjectOptions): Promise<Crea
|
|
|
27
27
|
|
|
28
28
|
const template = getTemplate(options.template);
|
|
29
29
|
const projectPath = target.path;
|
|
30
|
-
const files =
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
const files = [
|
|
31
|
+
...template.files(target.name, {
|
|
32
|
+
agentkitDependency: await resolveAgentKitDependency(),
|
|
33
|
+
}),
|
|
34
|
+
...(await loadDefaultSkillFiles()),
|
|
35
|
+
];
|
|
33
36
|
|
|
34
37
|
if (target.currentDirectory) {
|
|
35
38
|
await ensureNoFileCollisions(projectPath, files.map((file) => file.path));
|
|
@@ -126,6 +129,35 @@ async function resolveAgentKitDependency(): Promise<string> {
|
|
|
126
129
|
return packageJson.version;
|
|
127
130
|
}
|
|
128
131
|
|
|
132
|
+
async function loadDefaultSkillFiles(): Promise<TemplateFile[]> {
|
|
133
|
+
const sourceRoot = join(moduleDir, "templates", "skills");
|
|
134
|
+
const sourceFiles = await listFiles(sourceRoot);
|
|
135
|
+
|
|
136
|
+
return Promise.all(
|
|
137
|
+
sourceFiles.map(async (sourcePath) => ({
|
|
138
|
+
path: join("skills", relative(sourceRoot, sourcePath)).replaceAll("\\", "/"),
|
|
139
|
+
contents: await readFile(sourcePath, "utf8"),
|
|
140
|
+
})),
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function listFiles(directory: string): Promise<string[]> {
|
|
145
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
146
|
+
const files = await Promise.all(
|
|
147
|
+
entries.map(async (entry) => {
|
|
148
|
+
const path = join(directory, entry.name);
|
|
149
|
+
|
|
150
|
+
if (entry.isDirectory()) {
|
|
151
|
+
return listFiles(path);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return entry.isFile() ? [path] : [];
|
|
155
|
+
}),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
return files.flat().sort();
|
|
159
|
+
}
|
|
160
|
+
|
|
129
161
|
async function directoryExists(path: string): Promise<boolean> {
|
|
130
162
|
try {
|
|
131
163
|
const result = await stat(path);
|
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;
|
|
@@ -90,6 +118,37 @@ export type AgentFilesConfig =
|
|
|
90
118
|
maxUploadBytes?: number;
|
|
91
119
|
};
|
|
92
120
|
|
|
121
|
+
export type AgentKnowledgeSource =
|
|
122
|
+
| string
|
|
123
|
+
| {
|
|
124
|
+
path: string;
|
|
125
|
+
title?: string;
|
|
126
|
+
}
|
|
127
|
+
| {
|
|
128
|
+
url: string;
|
|
129
|
+
title?: string;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export type AgentKnowledgeEmbeddingProvider = "none" | "test" | "openai";
|
|
133
|
+
|
|
134
|
+
export type AgentKnowledgeEmbeddingConfig = {
|
|
135
|
+
provider?: AgentKnowledgeEmbeddingProvider;
|
|
136
|
+
model?: string;
|
|
137
|
+
dimensions?: number;
|
|
138
|
+
secret?: string;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export type AgentKnowledgeRetrievalConfig = {
|
|
142
|
+
topK?: number;
|
|
143
|
+
hybrid?: boolean;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export type AgentKnowledgeConfig = {
|
|
147
|
+
sources?: AgentKnowledgeSource[];
|
|
148
|
+
embedding?: AgentKnowledgeEmbeddingConfig;
|
|
149
|
+
retrieval?: AgentKnowledgeRetrievalConfig;
|
|
150
|
+
};
|
|
151
|
+
|
|
93
152
|
export type JsonSchema = {
|
|
94
153
|
type: string | string[];
|
|
95
154
|
properties?: Record<string, JsonSchema>;
|
|
@@ -157,6 +216,7 @@ export type AgentConfig = {
|
|
|
157
216
|
secrets: string[];
|
|
158
217
|
tools?: AgentTool[];
|
|
159
218
|
channels?: AgentChannel[];
|
|
219
|
+
knowledge?: AgentKnowledgeConfig;
|
|
160
220
|
access: {
|
|
161
221
|
mode: AccessMode;
|
|
162
222
|
};
|
|
@@ -184,6 +244,7 @@ export function websiteChannel(input: WebsiteChannelInput): WebsiteChannelConfig
|
|
|
184
244
|
access: input.access ?? { mode: "token" },
|
|
185
245
|
secrets: normalizeChannelSecrets(input.secrets ?? ["AGENTKIT_WEBSITE_CHANNEL_TOKEN"], "website channel"),
|
|
186
246
|
...(input.limits ? { limits: input.limits } : {}),
|
|
247
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "website channel") } : {}),
|
|
187
248
|
};
|
|
188
249
|
}
|
|
189
250
|
|
|
@@ -198,6 +259,7 @@ export function telegramChannel(input: TelegramChannelInput): TelegramChannelCon
|
|
|
198
259
|
),
|
|
199
260
|
allowedUpdates: input.allowedUpdates ?? ["message"],
|
|
200
261
|
...(input.limits ? { limits: input.limits } : {}),
|
|
262
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "telegram channel") } : {}),
|
|
201
263
|
};
|
|
202
264
|
}
|
|
203
265
|
|
|
@@ -211,6 +273,7 @@ export function whatsappChannel(input: WhatsappChannelInput): WhatsappChannelCon
|
|
|
211
273
|
`${input.provider} whatsapp channel`,
|
|
212
274
|
),
|
|
213
275
|
...(input.limits ? { limits: input.limits } : {}),
|
|
276
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, `${input.provider} whatsapp channel`) } : {}),
|
|
214
277
|
};
|
|
215
278
|
}
|
|
216
279
|
|
|
@@ -236,6 +299,41 @@ function normalizeChannelSecrets(secrets: string[], context: string): string[] {
|
|
|
236
299
|
return Array.from(uniqueSecrets).sort();
|
|
237
300
|
}
|
|
238
301
|
|
|
302
|
+
function normalizeChannelBuffer(input: ChannelBufferInput, context: string): ChannelBufferConfig {
|
|
303
|
+
if (input.mode === "off") {
|
|
304
|
+
return { mode: "off" };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (input.mode !== undefined && input.mode !== "debounce") {
|
|
308
|
+
throw new Error(`${context} buffer.mode must be "off" or "debounce".`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const buffer: ChannelBufferConfig = {
|
|
312
|
+
mode: "debounce",
|
|
313
|
+
quietWindowMs: input.quietWindowMs ?? 2500,
|
|
314
|
+
maxWaitMs: input.maxWaitMs ?? 12000,
|
|
315
|
+
maxMessages: input.maxMessages ?? 20,
|
|
316
|
+
maxChars: input.maxChars ?? 8000,
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
validatePositiveInteger(buffer.quietWindowMs, `${context} buffer.quietWindowMs`);
|
|
320
|
+
validatePositiveInteger(buffer.maxWaitMs, `${context} buffer.maxWaitMs`);
|
|
321
|
+
validatePositiveInteger(buffer.maxMessages, `${context} buffer.maxMessages`);
|
|
322
|
+
validatePositiveInteger(buffer.maxChars, `${context} buffer.maxChars`);
|
|
323
|
+
|
|
324
|
+
if (buffer.maxWaitMs < buffer.quietWindowMs) {
|
|
325
|
+
throw new Error(`${context} buffer.maxWaitMs must be greater than or equal to buffer.quietWindowMs.`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return buffer;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function validatePositiveInteger(value: number, field: string): void {
|
|
332
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
333
|
+
throw new Error(`${field} must be a positive integer.`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
239
337
|
export { loadAgentCapsule, findAgentCapsuleRoot } from "./runtime/config";
|
|
240
338
|
export { runAgentMessage, runAgentMessageFromCwd } from "./runtime/chat";
|
|
241
339
|
export { listConversationsFromCwd, getConversationFromCwd } from "./runtime/conversations";
|
|
@@ -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: {
|