@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/runtime/tools.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentTool, JsonSchema, ToolContext, ToolRuntimeContext } from "../index";
|
|
1
|
+
import type { AgentTool, JsonSchema, ToolContext, ToolRenderResult, ToolRuntimeContext } from "../index";
|
|
2
2
|
import type { SqliteAgentKitStore } from "../storage/sqlite";
|
|
3
3
|
import { createLocalDatabaseRunner } from "./database";
|
|
4
4
|
import { AgentKitError } from "./errors";
|
|
@@ -14,6 +14,7 @@ export type ToolCallResult = {
|
|
|
14
14
|
visibility: "user" | "internal";
|
|
15
15
|
input: unknown;
|
|
16
16
|
output: unknown;
|
|
17
|
+
rendered?: ToolRenderResult;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
export type ToolRuntime = {
|
|
@@ -97,10 +98,13 @@ async function executeToolCall(
|
|
|
97
98
|
validateSchema(output, tool.outputSchema, `tool "${tool.name}" output`);
|
|
98
99
|
}
|
|
99
100
|
|
|
101
|
+
const rendered = renderToolOutput(tool, input, output, options.runtime);
|
|
102
|
+
|
|
100
103
|
options.store.completeToolCall({
|
|
101
104
|
toolCallId: toolCall.id,
|
|
102
105
|
status: "completed",
|
|
103
106
|
output,
|
|
107
|
+
rendered,
|
|
104
108
|
secretValues,
|
|
105
109
|
});
|
|
106
110
|
|
|
@@ -110,6 +114,7 @@ async function executeToolCall(
|
|
|
110
114
|
visibility: tool.visibility ?? "user",
|
|
111
115
|
input,
|
|
112
116
|
output,
|
|
117
|
+
...(rendered ? { rendered } : {}),
|
|
113
118
|
};
|
|
114
119
|
} catch (error) {
|
|
115
120
|
const secretValues = collectConfiguredSecretValues(tool, options.env ?? process.env);
|
|
@@ -125,6 +130,121 @@ async function executeToolCall(
|
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
|
|
133
|
+
function renderToolOutput(
|
|
134
|
+
tool: AgentTool,
|
|
135
|
+
input: unknown,
|
|
136
|
+
output: unknown,
|
|
137
|
+
runtime: ToolRuntimeContext,
|
|
138
|
+
): ToolRenderResult | undefined {
|
|
139
|
+
if (!tool.render) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const rendered = tool.render(output, {
|
|
144
|
+
input,
|
|
145
|
+
runtime,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
if (typeof rendered === "string") {
|
|
149
|
+
return { text: rendered };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!isRecord(rendered) || typeof rendered.text !== "string" || rendered.text.trim().length === 0) {
|
|
153
|
+
throw new AgentKitError("tool_validation_error", `tool "${tool.name}" render must return a non-empty text string.`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (rendered.blocks !== undefined) {
|
|
157
|
+
if (!Array.isArray(rendered.blocks)) {
|
|
158
|
+
throw new AgentKitError("tool_validation_error", `tool "${tool.name}" render.blocks must be an array when provided.`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
for (const [index, block] of rendered.blocks.entries()) {
|
|
162
|
+
validateRenderBlock(block, `tool "${tool.name}" render.blocks[${index}]`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
text: rendered.text,
|
|
168
|
+
...(rendered.blocks ? { blocks: rendered.blocks } : {}),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function validateRenderBlock(block: unknown, label: string): void {
|
|
173
|
+
if (!isRecord(block)) {
|
|
174
|
+
throw new AgentKitError("tool_validation_error", `${label} must be an object.`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (block.type === "text") {
|
|
178
|
+
if (typeof block.text !== "string" || block.text.trim().length === 0) {
|
|
179
|
+
throw new AgentKitError("tool_validation_error", `${label}.text must be a non-empty string.`);
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (block.type === "card") {
|
|
185
|
+
if (typeof block.title !== "string" || block.title.trim().length === 0) {
|
|
186
|
+
throw new AgentKitError("tool_validation_error", `${label}.title must be a non-empty string.`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
validateOptionalString(block.subtitle, `${label}.subtitle`);
|
|
190
|
+
validateRenderFields(block.fields, `${label}.fields`);
|
|
191
|
+
validateRenderActions(block.actions, `${label}.actions`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
throw new AgentKitError("tool_validation_error", `${label}.type must be "text" or "card".`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function validateRenderFields(value: unknown, label: string): void {
|
|
199
|
+
if (value === undefined) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!Array.isArray(value)) {
|
|
204
|
+
throw new AgentKitError("tool_validation_error", `${label} must be an array when provided.`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
for (const [index, field] of value.entries()) {
|
|
208
|
+
if (!isRecord(field)) {
|
|
209
|
+
throw new AgentKitError("tool_validation_error", `${label}[${index}] must be an object.`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
validateRequiredString(field.label, `${label}[${index}].label`);
|
|
213
|
+
validateRequiredString(field.value, `${label}[${index}].value`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function validateRenderActions(value: unknown, label: string): void {
|
|
218
|
+
if (value === undefined) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!Array.isArray(value)) {
|
|
223
|
+
throw new AgentKitError("tool_validation_error", `${label} must be an array when provided.`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
for (const [index, action] of value.entries()) {
|
|
227
|
+
if (!isRecord(action)) {
|
|
228
|
+
throw new AgentKitError("tool_validation_error", `${label}[${index}] must be an object.`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
validateRequiredString(action.label, `${label}[${index}].label`);
|
|
232
|
+
validateOptionalString(action.href, `${label}[${index}].href`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function validateRequiredString(value: unknown, label: string): void {
|
|
237
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
238
|
+
throw new AgentKitError("tool_validation_error", `${label} must be a non-empty string.`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function validateOptionalString(value: unknown, label: string): void {
|
|
243
|
+
if (value !== undefined && typeof value !== "string") {
|
|
244
|
+
throw new AgentKitError("tool_validation_error", `${label} must be a string when provided.`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
128
248
|
function resolveToolSecrets(
|
|
129
249
|
tool: AgentTool,
|
|
130
250
|
env: Record<string, string | undefined>,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ConversationRecord, StoredRun, StoredToolCall } from "../storage/sqlite";
|
|
2
|
+
import { openCapsuleStore } from "../storage/sqlite";
|
|
3
|
+
import { loadAgentCapsule } from "./config";
|
|
4
|
+
import { AgentKitError } from "./errors";
|
|
5
|
+
|
|
6
|
+
export type ConversationTrace = ConversationRecord & {
|
|
7
|
+
runs: ConversationTraceRun[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type ConversationTraceRun = StoredRun & {
|
|
11
|
+
toolCalls: StoredToolCall[];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export async function getConversationTraceFromCwd(cwd: string, conversationId: string): Promise<ConversationTrace> {
|
|
15
|
+
if (!conversationId) {
|
|
16
|
+
throw new AgentKitError("validation_error", "Missing conversation id.");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const capsule = await loadAgentCapsule(cwd);
|
|
20
|
+
const store = await openCapsuleStore(capsule);
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const conversation = store.getConversation(conversationId);
|
|
24
|
+
|
|
25
|
+
if (!conversation) {
|
|
26
|
+
throw new AgentKitError("conversation_not_found", `Conversation "${conversationId}" was not found.`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const runs = store.listRunsForConversation(conversation.id).map((run) => ({
|
|
30
|
+
...run,
|
|
31
|
+
toolCalls: store.listToolCallsForRun(run.id),
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
...conversation,
|
|
36
|
+
runs,
|
|
37
|
+
};
|
|
38
|
+
} finally {
|
|
39
|
+
store.close();
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/storage/sqlite.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { DatabaseArgs, DatabaseResult, DatabaseRow, DatabaseStatement } fro
|
|
|
6
6
|
import type { AgentMessageRole, ProviderRunResult } from "../providers";
|
|
7
7
|
import type { LoadedAgentCapsule } from "../runtime/config";
|
|
8
8
|
import { AgentKitError } from "../runtime/errors";
|
|
9
|
+
import { KNOWLEDGE_MIGRATION_ID, KNOWLEDGE_SCHEMA_SQL } from "../runtime/knowledge/schema";
|
|
9
10
|
|
|
10
11
|
export type ConversationSummary = {
|
|
11
12
|
id: string;
|
|
@@ -41,12 +42,30 @@ export type StoredToolCall = {
|
|
|
41
42
|
visibility: ToolCallVisibility;
|
|
42
43
|
input: unknown;
|
|
43
44
|
output: unknown;
|
|
45
|
+
rendered: unknown;
|
|
44
46
|
status: ToolCallStatus;
|
|
45
47
|
startedAt: string;
|
|
46
48
|
completedAt: string | null;
|
|
47
49
|
errorMessage: string | null;
|
|
48
50
|
};
|
|
49
51
|
|
|
52
|
+
export type StoredRun = {
|
|
53
|
+
id: string;
|
|
54
|
+
conversationId: string | null;
|
|
55
|
+
provider: string;
|
|
56
|
+
model: string;
|
|
57
|
+
status: RunStatus;
|
|
58
|
+
usage: {
|
|
59
|
+
inputTokens: number | null;
|
|
60
|
+
outputTokens: number | null;
|
|
61
|
+
totalTokens: number | null;
|
|
62
|
+
};
|
|
63
|
+
startedAt: string;
|
|
64
|
+
completedAt: string | null;
|
|
65
|
+
errorCode: string | null;
|
|
66
|
+
errorMessage: string | null;
|
|
67
|
+
};
|
|
68
|
+
|
|
50
69
|
export type PersistedChatRun = {
|
|
51
70
|
conversationId: string;
|
|
52
71
|
runId: string;
|
|
@@ -153,6 +172,17 @@ const MIGRATIONS = [
|
|
|
153
172
|
ADD COLUMN visibility TEXT NOT NULL DEFAULT 'user';
|
|
154
173
|
`,
|
|
155
174
|
},
|
|
175
|
+
{
|
|
176
|
+
id: KNOWLEDGE_MIGRATION_ID,
|
|
177
|
+
sql: KNOWLEDGE_SCHEMA_SQL,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: "0007_add_tool_call_rendered",
|
|
181
|
+
sql: `
|
|
182
|
+
ALTER TABLE tool_calls
|
|
183
|
+
ADD COLUMN rendered_json TEXT;
|
|
184
|
+
`,
|
|
185
|
+
},
|
|
156
186
|
] as const;
|
|
157
187
|
|
|
158
188
|
export async function openCapsuleStore(capsule: LoadedAgentCapsule): Promise<SqliteAgentKitStore> {
|
|
@@ -457,6 +487,7 @@ export class SqliteAgentKitStore {
|
|
|
457
487
|
toolCallId: string;
|
|
458
488
|
status: ToolCallStatus;
|
|
459
489
|
output?: unknown;
|
|
490
|
+
rendered?: unknown;
|
|
460
491
|
completedAt?: string;
|
|
461
492
|
errorMessage?: string;
|
|
462
493
|
secretValues?: string[];
|
|
@@ -469,6 +500,7 @@ export class SqliteAgentKitStore {
|
|
|
469
500
|
SET
|
|
470
501
|
status = $status,
|
|
471
502
|
output_json = $outputJson,
|
|
503
|
+
rendered_json = $renderedJson,
|
|
472
504
|
completed_at = $completedAt,
|
|
473
505
|
error_message = $errorMessage
|
|
474
506
|
WHERE id = $toolCallId
|
|
@@ -478,6 +510,7 @@ export class SqliteAgentKitStore {
|
|
|
478
510
|
$toolCallId: input.toolCallId,
|
|
479
511
|
$status: input.status,
|
|
480
512
|
$outputJson: input.output === undefined ? null : serializeJson(input.output, input.secretValues),
|
|
513
|
+
$renderedJson: input.rendered === undefined ? null : serializeJson(input.rendered, input.secretValues),
|
|
481
514
|
$completedAt: input.completedAt ?? new Date().toISOString(),
|
|
482
515
|
$errorMessage: redactSecrets(input.errorMessage ?? null, input.secretValues),
|
|
483
516
|
});
|
|
@@ -550,6 +583,35 @@ export class SqliteAgentKitStore {
|
|
|
550
583
|
});
|
|
551
584
|
}
|
|
552
585
|
|
|
586
|
+
listRunsForConversation(conversationId: string): StoredRun[] {
|
|
587
|
+
return this.sqlite(() => {
|
|
588
|
+
const rows = this.db
|
|
589
|
+
.prepare(
|
|
590
|
+
`
|
|
591
|
+
SELECT
|
|
592
|
+
id,
|
|
593
|
+
conversation_id,
|
|
594
|
+
provider,
|
|
595
|
+
model,
|
|
596
|
+
status,
|
|
597
|
+
input_tokens,
|
|
598
|
+
output_tokens,
|
|
599
|
+
total_tokens,
|
|
600
|
+
started_at,
|
|
601
|
+
completed_at,
|
|
602
|
+
error_code,
|
|
603
|
+
error_message
|
|
604
|
+
FROM runs
|
|
605
|
+
WHERE conversation_id = $conversationId
|
|
606
|
+
ORDER BY started_at ASC
|
|
607
|
+
`,
|
|
608
|
+
)
|
|
609
|
+
.all({ $conversationId: conversationId }) as SqliteRow[];
|
|
610
|
+
|
|
611
|
+
return rows.map(storedRunFromRow);
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
|
|
553
615
|
listToolCallsForRun(runId: string): StoredToolCall[] {
|
|
554
616
|
return this.sqlite(() => {
|
|
555
617
|
const rows = this.db
|
|
@@ -563,6 +625,7 @@ export class SqliteAgentKitStore {
|
|
|
563
625
|
visibility,
|
|
564
626
|
input_json,
|
|
565
627
|
output_json,
|
|
628
|
+
rendered_json,
|
|
566
629
|
status,
|
|
567
630
|
started_at,
|
|
568
631
|
completed_at,
|
|
@@ -578,6 +641,54 @@ export class SqliteAgentKitStore {
|
|
|
578
641
|
});
|
|
579
642
|
}
|
|
580
643
|
|
|
644
|
+
applyApplicationMigrations(migrations: Array<{ id: string; sql: string }>): { applied: string[]; skipped: string[] } {
|
|
645
|
+
return this.sqlite(() => {
|
|
646
|
+
if (migrations.length === 0) {
|
|
647
|
+
return { applied: [], skipped: [] };
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
this.db.exec(`
|
|
651
|
+
CREATE TABLE IF NOT EXISTS agentkit_app_migrations (
|
|
652
|
+
id TEXT PRIMARY KEY,
|
|
653
|
+
applied_at TEXT NOT NULL
|
|
654
|
+
)
|
|
655
|
+
`);
|
|
656
|
+
|
|
657
|
+
const applied = new Set(
|
|
658
|
+
(
|
|
659
|
+
this.db.prepare("SELECT id FROM agentkit_app_migrations").all() as Array<{
|
|
660
|
+
id: string;
|
|
661
|
+
}>
|
|
662
|
+
).map((row) => row.id),
|
|
663
|
+
);
|
|
664
|
+
const result = {
|
|
665
|
+
applied: [] as string[],
|
|
666
|
+
skipped: [] as string[],
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
for (const migration of migrations) {
|
|
670
|
+
if (applied.has(migration.id)) {
|
|
671
|
+
result.skipped.push(migration.id);
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const statements = splitSqlStatements(migration.sql);
|
|
676
|
+
this.transaction(() => {
|
|
677
|
+
for (const statement of statements) {
|
|
678
|
+
this.db.exec(statement);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
this.db
|
|
682
|
+
.prepare("INSERT INTO agentkit_app_migrations (id, applied_at) VALUES ($id, $appliedAt)")
|
|
683
|
+
.run({ $id: migration.id, $appliedAt: new Date().toISOString() });
|
|
684
|
+
});
|
|
685
|
+
result.applied.push(migration.id);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
return result;
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
|
|
581
692
|
applyApplicationSchema(source: string): void {
|
|
582
693
|
this.sqlite(() => {
|
|
583
694
|
const statements = splitSqlStatements(source);
|
|
@@ -785,6 +896,31 @@ function storedMessageFromRow(row: SqliteRow): StoredMessage {
|
|
|
785
896
|
};
|
|
786
897
|
}
|
|
787
898
|
|
|
899
|
+
function storedRunFromRow(row: SqliteRow): StoredRun {
|
|
900
|
+
const status = String(row.status);
|
|
901
|
+
|
|
902
|
+
if (status !== "running" && status !== "completed" && status !== "failed") {
|
|
903
|
+
throw new AgentKitError("storage_error", `Invalid stored run status "${status}".`);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
return {
|
|
907
|
+
id: String(row.id),
|
|
908
|
+
conversationId: row.conversation_id === null ? null : String(row.conversation_id),
|
|
909
|
+
provider: String(row.provider),
|
|
910
|
+
model: String(row.model),
|
|
911
|
+
status,
|
|
912
|
+
usage: {
|
|
913
|
+
inputTokens: nullableNumber(row.input_tokens),
|
|
914
|
+
outputTokens: nullableNumber(row.output_tokens),
|
|
915
|
+
totalTokens: nullableNumber(row.total_tokens),
|
|
916
|
+
},
|
|
917
|
+
startedAt: String(row.started_at),
|
|
918
|
+
completedAt: row.completed_at === null ? null : String(row.completed_at),
|
|
919
|
+
errorCode: row.error_code === null ? null : String(row.error_code),
|
|
920
|
+
errorMessage: row.error_message === null ? null : String(row.error_message),
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
|
|
788
924
|
function storedToolCallFromRow(row: SqliteRow): StoredToolCall {
|
|
789
925
|
const status = String(row.status);
|
|
790
926
|
const visibility = String(row.visibility);
|
|
@@ -805,6 +941,7 @@ function storedToolCallFromRow(row: SqliteRow): StoredToolCall {
|
|
|
805
941
|
visibility,
|
|
806
942
|
input: parseStoredJson(row.input_json),
|
|
807
943
|
output: row.output_json === null ? undefined : parseStoredJson(row.output_json),
|
|
944
|
+
rendered: row.rendered_json === null ? undefined : parseStoredJson(row.rendered_json),
|
|
808
945
|
status,
|
|
809
946
|
startedAt: String(row.started_at),
|
|
810
947
|
completedAt: row.completed_at === null ? null : String(row.completed_at),
|
|
@@ -812,6 +949,10 @@ function storedToolCallFromRow(row: SqliteRow): StoredToolCall {
|
|
|
812
949
|
};
|
|
813
950
|
}
|
|
814
951
|
|
|
952
|
+
function nullableNumber(value: unknown): number | null {
|
|
953
|
+
return value === null || value === undefined ? null : Number(value);
|
|
954
|
+
}
|
|
955
|
+
|
|
815
956
|
function parseStoredJson(value: unknown): unknown {
|
|
816
957
|
if (typeof value !== "string") {
|
|
817
958
|
return value;
|
package/src/templates/blank.ts
CHANGED
|
@@ -147,11 +147,13 @@ When the owner opens this folder in Codex, Claude Code, or another coding agent
|
|
|
147
147
|
|
|
148
148
|
Start building immediately:
|
|
149
149
|
|
|
150
|
-
-
|
|
150
|
+
- Start with \`skills/agentkit-capsule/SKILL.md\`, then use \`npm run agentkit -- docs llms\` as the docs router.
|
|
151
|
+
- Create or update \`AGENT_SPEC.md\` from the owner's request with \`npm run agentkit -- spec init --brief "<owner request>"\`; the owner should not fill this file by hand before work starts.
|
|
151
152
|
- Infer the first useful version from the owner's request.
|
|
152
153
|
- Edit \`prompts/instructions.md\` for the agent behavior.
|
|
153
154
|
- Edit \`agentkit.config.ts\` for provider, tools, secrets, access, and storage.
|
|
154
155
|
- Add TypeScript tools under \`tools/\` when the requested agent needs actions or external data.
|
|
156
|
+
- Add \`sync.ts\`, \`seed.sql\`, and ordered \`migrations/*.sql\` when the requested agent depends on external catalogs or production-shaped data changes.
|
|
155
157
|
- Do not wait for a wizard or recipe. AgentKit provides the scaffold and contract; you decide the implementation from the owner's brief.
|
|
156
158
|
- Ask follow-up questions only when missing information blocks a safe local implementation.
|
|
157
159
|
- State assumptions in the final response.
|
|
@@ -162,6 +164,9 @@ Start building immediately:
|
|
|
162
164
|
- \`npm run dev\`: run the local Agent Capsule runtime.
|
|
163
165
|
- \`npm run chat -- --message "hello"\`: send one local chat message.
|
|
164
166
|
- \`npm run eval\`: run agent evals.
|
|
167
|
+
- \`npm run agentkit -- spec check\`: verify the local agent implementation contract exists.
|
|
168
|
+
- \`npm run agentkit -- eval from-conversation <conversation-id>\`: turn a real conversation into a regression eval.
|
|
169
|
+
- \`npm run agentkit -- conversations trace <conversation-id>\`: inspect messages, runs, tool calls, inputs, outputs, rendered output, and final responses.
|
|
165
170
|
- \`npm run agentkit -- tool <name> --input fixtures/input.json\`: run one registered tool directly.
|
|
166
171
|
- \`npm run agentkit -- db migrate\`: apply internal migrations and \`schema.sql\` locally.
|
|
167
172
|
- \`npm run agentkit -- db reset --yes\`: recreate the local SQLite database and reapply schema.
|
|
@@ -170,7 +175,8 @@ Start building immediately:
|
|
|
170
175
|
- \`npm run agentkit -- inspect\`: print machine-readable capsule state.
|
|
171
176
|
- \`printf %s "$VALUE" | npm run agentkit -- env set <NAME> --stdin\`: write a local secret value to ignored \`.env\` without putting it in shell history.
|
|
172
177
|
- \`npm run agentkit -- env list\`: list local secret names without printing values.
|
|
173
|
-
- \`npm run agentkit -- docs
|
|
178
|
+
- \`npm run agentkit -- docs llms\`: print the lightweight AgentKit docs router.
|
|
179
|
+
- \`npm run agentkit -- docs full\`: print the full AgentKit contract path only when a skill asks for it.
|
|
174
180
|
|
|
175
181
|
## Testing With A UI
|
|
176
182
|
|
|
@@ -211,7 +217,7 @@ export const myTool = defineTool({
|
|
|
211
217
|
|
|
212
218
|
Use \`ctx.db\` as the canonical helper. \`ctx.database\` and \`ctx.storage.sql\` are aliases. Use \`ctx.db.batch([...])\` for atomic writes; local tools can also use \`ctx.db.transaction(async (tx) => ...)\`. Do not import local database drivers or Node-only APIs in tools. AgentKit owns local and hosted database routing.
|
|
213
219
|
|
|
214
|
-
\`schema.sql\` is an idempotent bootstrap file
|
|
220
|
+
\`schema.sql\` is an idempotent bootstrap file. Use \`CREATE TABLE IF NOT EXISTS\`, \`CREATE INDEX IF NOT EXISTS\`, and safe additive changes. Use ordered \`migrations/*.sql\` for production-shaped schema evolution; \`npm run agentkit -- db migrate\` applies unapplied local migrations before \`schema.sql\`.
|
|
215
221
|
|
|
216
222
|
## Hosted Deploy
|
|
217
223
|
|
|
@@ -251,8 +257,10 @@ Example owner request:
|
|
|
251
257
|
Turn the request into a working local capsule:
|
|
252
258
|
|
|
253
259
|
- Update \`prompts/instructions.md\` with domain-specific behavior, boundaries, intake questions, and escalation rules.
|
|
260
|
+
- Create or update \`AGENT_SPEC.md\` with \`npm run agentkit -- spec init --brief "<owner request>"\`. The owner gives the general idea; the coding agent turns it into the structured contract.
|
|
254
261
|
- Update \`agentkit.config.ts\` when tools, secrets, provider, or access rules change.
|
|
255
262
|
- Add TypeScript tools under \`tools/\` for real actions or external data.
|
|
263
|
+
- Use \`npm run agentkit -- sync init\` when the agent needs catalog sync, fixture seed data, or ordered migrations.
|
|
256
264
|
- Keep the first version runnable with \`test/fake\` unless the owner explicitly asks for a real provider.
|
|
257
265
|
- Do not use a wizard or recipe. Build the capsule directly from the scaffold, the AgentKit contract, and the owner's brief.
|
|
258
266
|
- Make practical assumptions and list them in your final response.
|
|
@@ -305,12 +313,14 @@ If you add a tool, also run a fake-provider tool smoke test:
|
|
|
305
313
|
npm run agentkit -- tool tool_name --input '{}'
|
|
306
314
|
\`\`\`
|
|
307
315
|
|
|
308
|
-
For the
|
|
316
|
+
For the lightweight docs router, read the path printed by:
|
|
309
317
|
|
|
310
318
|
\`\`\`sh
|
|
311
|
-
npm run agentkit -- docs
|
|
319
|
+
npm run agentkit -- docs llms
|
|
312
320
|
\`\`\`
|
|
313
321
|
|
|
322
|
+
Read the full framework contract with \`npm run agentkit -- docs full\` only when a skill asks for it.
|
|
323
|
+
|
|
314
324
|
## Hosted Deploy
|
|
315
325
|
|
|
316
326
|
This capsule is hosted-deploy ready by default.
|
|
@@ -343,6 +353,7 @@ Use AgentKit conventions when editing this project.
|
|
|
343
353
|
- Production secrets must be managed secrets, not committed files.
|
|
344
354
|
- Keep required local secret names in \`.env.schema\` and values in ignored \`.env\`. AgentKit local commands load \`.env\` directly.
|
|
345
355
|
- Treat the owner's natural-language request as the brief and start implementing inside this capsule.
|
|
356
|
+
- Start with \`skills/agentkit-capsule/SKILL.md\` when the task is not obvious.
|
|
346
357
|
`,
|
|
347
358
|
},
|
|
348
359
|
{
|
|
@@ -857,6 +857,8 @@ Esta é uma AgentKit Agent Capsule para a Clara, atendente em português de um c
|
|
|
857
857
|
|
|
858
858
|
A Clara conversa com clientes, coleta nome, email e telefone, consulta disponibilidade e agenda consultas em slots de 30 minutos. Ela também consulta e altera o próprio horário do cliente usando email e telefone como verificação mínima.
|
|
859
859
|
|
|
860
|
+
Quando o dono pedir mudanças em linguagem natural, crie ou atualize \`AGENT_SPEC.md\` com \`npm run agentkit -- spec init --brief "<pedido do dono>"\`. O dono dá a ideia geral; o agente de código transforma isso no contrato estruturado.
|
|
861
|
+
|
|
860
862
|
## Regras de Produto
|
|
861
863
|
|
|
862
864
|
- Persona: Clara, atendente humana, simpática e objetiva.
|
|
@@ -885,9 +887,13 @@ A Clara conversa com clientes, coleta nome, email e telefone, consulta disponibi
|
|
|
885
887
|
- \`npm run agentkit -- tool consultar_consulta --input '{"email":"ana@example.com","telefone":"11999999999"}'\`: consultar uma consulta.
|
|
886
888
|
- \`npm run agentkit -- tool alterar_consulta --input '{"email":"ana@example.com","telefone":"11999999999","novaData":"2099-01-06","novoHorario":"10:30","confirmadoPeloCliente":true}'\`: alterar uma consulta confirmada.
|
|
887
889
|
- \`npm run eval\`: rodar evals.
|
|
890
|
+
- \`npm run agentkit -- spec check\`: validar o contrato local da implementação.
|
|
891
|
+
- \`npm run agentkit -- eval from-conversation <conversation-id>\`: transformar uma conversa real em eval de regressão.
|
|
892
|
+
- \`npm run agentkit -- conversations trace <conversation-id>\`: inspecionar mensagens, runs, ferramentas, inputs, outputs, renderização e resposta final.
|
|
888
893
|
- \`npm run dev\`: rodar a runtime local.
|
|
889
894
|
- \`npm run agentkit -- inspect\`: imprimir o estado da cápsula.
|
|
890
|
-
- \`npm run agentkit -- docs
|
|
895
|
+
- \`npm run agentkit -- docs llms\`: imprimir o roteador leve da documentação AgentKit.
|
|
896
|
+
- \`npm run agentkit -- docs full\`: imprimir o contrato completo do AgentKit somente quando uma skill pedir.
|
|
891
897
|
|
|
892
898
|
## Teste Com UI
|
|
893
899
|
|
|
@@ -899,10 +905,12 @@ A Clara conversa com clientes, coleta nome, email e telefone, consulta disponibi
|
|
|
899
905
|
## Regras de Implementação
|
|
900
906
|
|
|
901
907
|
- Use \`ctx.db\` nas ferramentas. Não importe drivers SQLite, Turso ou Node-only APIs.
|
|
902
|
-
- Mantenha \`schema.sql\` idempotente com \`CREATE TABLE IF NOT EXISTS\` e \`CREATE INDEX IF NOT EXISTS\`.
|
|
908
|
+
- Mantenha \`schema.sql\` idempotente com \`CREATE TABLE IF NOT EXISTS\` e \`CREATE INDEX IF NOT EXISTS\`. Use \`migrations/*.sql\` ordenadas para evolução de schema com cara de produção.
|
|
909
|
+
- Use \`npm run agentkit -- sync init\` quando a agente depender de catálogo externo, fixture local ou seed padronizado.
|
|
903
910
|
- Mantenha segredos em \`.env\`, nunca em arquivos versionados.
|
|
904
911
|
- Não espere wizard ou recipe. AgentKit fornece o scaffold e o contrato; implemente diretamente conforme o brief do dono.
|
|
905
912
|
- Para trocar para um provider real, o dono deve escolher OpenRouter, OpenAI, Anthropic ou outro provider suportado. Depois edite \`agentkit.config.ts\`, atualize \`.env.schema\` e configure secrets locais/hosted.
|
|
913
|
+
- Quando a próxima ação não for óbvia, comece por \`skills/agentkit-capsule/SKILL.md\`.
|
|
906
914
|
`,
|
|
907
915
|
},
|
|
908
916
|
{
|
|
@@ -931,6 +939,13 @@ npm run chat -- --message "Oi, quero marcar uma consulta."
|
|
|
931
939
|
|
|
932
940
|
A cápsula começa com \`test/fake\`. Isso valida caminhos determinísticos, mas não prova qualidade de conversa natural.
|
|
933
941
|
|
|
942
|
+
Se o dono pedir uma mudança grande, crie ou atualize o contrato de implementação:
|
|
943
|
+
|
|
944
|
+
\`\`\`sh
|
|
945
|
+
npm run agentkit -- spec init --brief "<pedido do dono>"
|
|
946
|
+
npm run agentkit -- spec check
|
|
947
|
+
\`\`\`
|
|
948
|
+
|
|
934
949
|
## Ferramentas
|
|
935
950
|
|
|
936
951
|
- \`listar_horarios_disponiveis\`: recebe \`data\` em \`YYYY-MM-DD\` e retorna slots livres.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentkit-build-agent
|
|
3
|
+
description: Use when the owner gives a natural-language brief for a new or changed AgentKit agent and expects the coding agent to turn it into a working local capsule with prompts, tools, schema, evals, and verification.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build An AgentKit Agent
|
|
7
|
+
|
|
8
|
+
Use this when the owner asks for an agent in plain language.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. Read `agentkit.config.ts`, `prompts/instructions.md`, `schema.sql`, `evals/`, and existing `tools/`.
|
|
13
|
+
2. If `AGENT_SPEC.md` does not exist, create it from the owner's plain-language request with `npm run agentkit -- spec init --brief "<owner request>"`. If it exists, update it directly before changing behavior.
|
|
14
|
+
3. Infer the first useful local version from the owner's brief and the spec. Do not ask the owner to fill a form.
|
|
15
|
+
4. Edit `prompts/instructions.md` for behavior, boundaries, intake questions, escalation rules, and tool-use policy.
|
|
16
|
+
5. Add tools only when the agent needs action, live data, authorization-sensitive data, or durable writes.
|
|
17
|
+
6. Add database tables to `schema.sql` or ordered `migrations/*.sql` when the agent owns records.
|
|
18
|
+
7. Add `sync.ts` and `seed.sql` with `npm run agentkit -- sync init` when the agent depends on external catalogs or recurring imports.
|
|
19
|
+
8. Add or update evals for the main flow. Prefer multi-turn `turns` evals for real conversations.
|
|
20
|
+
9. Keep the capsule runnable on `test/fake` unless the owner has chosen a real provider.
|
|
21
|
+
|
|
22
|
+
## Templates
|
|
23
|
+
|
|
24
|
+
Use these only when they match the brief:
|
|
25
|
+
|
|
26
|
+
- `templates/support-agent.instructions.md`
|
|
27
|
+
- `templates/appointment-intake.instructions.md`
|
|
28
|
+
- `templates/sales-qualifier.instructions.md`
|
|
29
|
+
|
|
30
|
+
For prompt-only work, use `skills/agentkit-prompts/SKILL.md`.
|
|
31
|
+
For database-backed tools, use `skills/agentkit-database/SKILL.md`.
|
|
32
|
+
|
|
33
|
+
## Verification
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npm run typecheck
|
|
37
|
+
npm run agentkit -- inspect
|
|
38
|
+
npm run chat -- --message "hello"
|
|
39
|
+
npm run eval
|
|
40
|
+
npm run agentkit -- spec check
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
If a tool was added:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm run agentkit -- tool <tool_name> --input '<json>'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Final Response
|
|
50
|
+
|
|
51
|
+
Summarize the files changed, assumptions made, verification results, and whether the behavior was tested with `test/fake` or a real provider selected by the owner.
|
package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
You are an appointment and intake agent.
|
|
2
|
+
|
|
3
|
+
Goal:
|
|
4
|
+
- Collect the information needed to understand the request.
|
|
5
|
+
- Offer available times only after checking availability through tools.
|
|
6
|
+
- Confirm the exact date, time, name, and contact details before saving.
|
|
7
|
+
|
|
8
|
+
Required intake:
|
|
9
|
+
- Full name
|
|
10
|
+
- Contact method
|
|
11
|
+
- Reason for visit
|
|
12
|
+
- Preferred date or time window
|
|
13
|
+
- Any urgency or special constraints
|
|
14
|
+
|
|
15
|
+
Rules:
|
|
16
|
+
- Do not diagnose, promise outcomes, or provide emergency guidance beyond directing urgent cases to appropriate human or emergency support.
|
|
17
|
+
- Do not create, change, or cancel an appointment without explicit user confirmation.
|
|
18
|
+
- Do not invent availability.
|
|
19
|
+
- Use the scheduling tools for availability and writes.
|
|
20
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
You are a sales qualification agent.
|
|
2
|
+
|
|
3
|
+
Goal:
|
|
4
|
+
- Understand the user's current situation, urgency, budget range, authority, and desired outcome.
|
|
5
|
+
- Identify whether the lead is a fit for the configured offer.
|
|
6
|
+
- Capture structured lead details through tools when available.
|
|
7
|
+
|
|
8
|
+
Behavior:
|
|
9
|
+
- Ask one focused question at a time.
|
|
10
|
+
- Avoid pressure and exaggerated claims.
|
|
11
|
+
- Be clear about what is known, unknown, and next.
|
|
12
|
+
- Escalate to a human when the user asks for pricing exceptions, legal terms, procurement details, or custom commitments.
|
|
13
|
+
|
|
14
|
+
Rules:
|
|
15
|
+
- Do not invent pricing, discounts, case studies, or availability.
|
|
16
|
+
- Do not expose internal lead scores or qualification labels.
|
|
17
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
You are a focused support agent.
|
|
2
|
+
|
|
3
|
+
Help users resolve the current issue clearly and efficiently.
|
|
4
|
+
|
|
5
|
+
Behavior:
|
|
6
|
+
- Ask for the minimum missing context needed to help.
|
|
7
|
+
- Use tools when order, account, booking, or case status is needed.
|
|
8
|
+
- Do not invent status, policy, price, or availability.
|
|
9
|
+
- Explain next steps in plain language.
|
|
10
|
+
- Escalate when the request involves billing disputes, safety, legal issues, account ownership, or anything outside the configured tools.
|
|
11
|
+
|
|
12
|
+
Boundaries:
|
|
13
|
+
- Do not claim to have changed anything unless a tool confirms it.
|
|
14
|
+
- Do not expose internal tool output, IDs, scores, secrets, or logs.
|
|
15
|
+
- If a tool fails, say what could not be verified and ask for a safe next step.
|
|
16
|
+
|