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

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 (142) hide show
  1. package/README.md +68 -6
  2. package/docs/guides/add-channel.md +189 -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 +128 -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-evolution.md +121 -0
  11. package/docs/guides/connect-whatsapp-uazapi.md +126 -0
  12. package/docs/guides/connect-whatsapp-zapster.md +112 -8
  13. package/docs/guides/create-agent.md +45 -4
  14. package/docs/guides/debug-channel.md +147 -0
  15. package/docs/guides/improve-from-production.md +151 -0
  16. package/docs/guides/prepare-deploy.md +47 -17
  17. package/docs/guides/replay-production-traces.md +72 -0
  18. package/docs/guides/run-evals.md +147 -20
  19. package/docs/guides/security-rules.md +7 -6
  20. package/docs/guides/send-feedback.md +135 -0
  21. package/docs/guides/use-provider.md +27 -3
  22. package/docs/llms-full.txt +348 -55
  23. package/docs/llms.txt +62 -7
  24. package/package.json +2 -5
  25. package/src/cli/args.ts +57 -0
  26. package/src/cli/cloud-client.ts +377 -0
  27. package/src/cli/commands/channels.ts +1586 -0
  28. package/src/cli/commands/feedback.ts +438 -0
  29. package/src/cli/commands/knowledge.ts +136 -0
  30. package/src/cli/commands/transcribe.ts +171 -0
  31. package/src/cli/constants.ts +4 -0
  32. package/src/cli/deploy-chat-ui.ts +535 -0
  33. package/src/cli/deploy-readiness.ts +481 -0
  34. package/src/cli/flags.ts +162 -0
  35. package/src/cli/help.ts +236 -0
  36. package/src/cli/index.ts +1167 -1005
  37. package/src/cli/process.ts +31 -0
  38. package/src/cloud/artifact.ts +139 -0
  39. package/src/cloud/client.ts +80 -0
  40. package/src/cloud/contracts.ts +63 -0
  41. package/src/cloud/index.ts +3 -0
  42. package/src/create-project.ts +21 -6
  43. package/src/index.ts +517 -8
  44. package/src/providers/pi.ts +70 -16
  45. package/src/providers/test.ts +88 -1
  46. package/src/providers/types.ts +7 -0
  47. package/src/runtime/channel-buffer.ts +30 -0
  48. package/src/runtime/channel-test-harness.ts +21 -1
  49. package/src/runtime/channels/discord.ts +896 -0
  50. package/src/runtime/channels/generic-webhook.ts +225 -0
  51. package/src/runtime/channels/slack.ts +646 -0
  52. package/src/runtime/channels/telegram.ts +466 -23
  53. package/src/runtime/channels/whatsapp-evolution.ts +1357 -0
  54. package/src/runtime/channels/whatsapp-meta.ts +9 -0
  55. package/src/runtime/channels/whatsapp-uazapi.ts +1327 -0
  56. package/src/runtime/channels/whatsapp-zapster.ts +677 -40
  57. package/src/runtime/channels.ts +87 -4
  58. package/src/runtime/chat.ts +130 -38
  59. package/src/runtime/config.ts +519 -19
  60. package/src/runtime/core/manifest.ts +103 -5
  61. package/src/runtime/core/targets.ts +5 -5
  62. package/src/runtime/database.ts +93 -2
  63. package/src/runtime/db-commands.ts +9 -0
  64. package/src/runtime/deploy-readiness.ts +46 -4
  65. package/src/runtime/deploy.ts +1 -1
  66. package/src/runtime/dev-server.ts +779 -45
  67. package/src/runtime/env.ts +8 -3
  68. package/src/runtime/evals.ts +589 -43
  69. package/src/runtime/improve.ts +868 -0
  70. package/src/runtime/inspect.ts +194 -4
  71. package/src/runtime/integrations/composio.ts +423 -0
  72. package/src/runtime/knowledge/chunk.ts +333 -0
  73. package/src/runtime/knowledge/config.ts +135 -0
  74. package/src/runtime/knowledge/embeddings.ts +133 -0
  75. package/src/runtime/knowledge/ingest.ts +521 -0
  76. package/src/runtime/knowledge/prompt-policy.ts +30 -0
  77. package/src/runtime/knowledge/retrieve.ts +303 -0
  78. package/src/runtime/knowledge/schema.ts +100 -0
  79. package/src/runtime/knowledge/tool.ts +64 -0
  80. package/src/runtime/knowledge/vector.ts +258 -0
  81. package/src/runtime/prompt-context.ts +141 -0
  82. package/src/runtime/runtime-contract.ts +86 -8
  83. package/src/runtime/skills.ts +95 -0
  84. package/src/runtime/spec.ts +152 -0
  85. package/src/runtime/sync.ts +144 -0
  86. package/src/runtime/targets/cloudflare/build.ts +1468 -203
  87. package/src/runtime/targets/container/server.ts +1 -1
  88. package/src/runtime/targets/vps/deploy.ts +26 -9
  89. package/src/runtime/tool-runner.ts +9 -1
  90. package/src/runtime/tools.ts +128 -2
  91. package/src/runtime/traces.ts +41 -0
  92. package/src/runtime/transcription.ts +483 -0
  93. package/src/storage/sqlite.ts +149 -3
  94. package/src/templates/blank.ts +76 -17
  95. package/src/templates/dentista.ts +1011 -0
  96. package/src/templates/index.ts +2 -0
  97. package/src/templates/skills/agentkit-build-agent/SKILL.md +52 -0
  98. package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md +21 -0
  99. package/src/templates/skills/agentkit-build-agent/templates/sales-qualifier.instructions.md +17 -0
  100. package/src/templates/skills/agentkit-build-agent/templates/support-agent.instructions.md +16 -0
  101. package/src/templates/skills/agentkit-capsule/SKILL.md +70 -0
  102. package/src/templates/skills/agentkit-capsule/references/docs-router.md +15 -0
  103. package/src/templates/skills/agentkit-channels/SKILL.md +127 -0
  104. package/src/templates/skills/agentkit-channels/references/channel-buffering.md +65 -0
  105. package/src/templates/skills/agentkit-channels/references/channel-debugging.md +66 -0
  106. package/src/templates/skills/agentkit-channels/references/discord.md +93 -0
  107. package/src/templates/skills/agentkit-channels/references/slack.md +56 -0
  108. package/src/templates/skills/agentkit-channels/references/telegram.md +72 -0
  109. package/src/templates/skills/agentkit-channels/references/whatsapp-evolution.md +57 -0
  110. package/src/templates/skills/agentkit-channels/references/whatsapp-uazapi.md +61 -0
  111. package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +77 -0
  112. package/src/templates/skills/agentkit-database/SKILL.md +45 -0
  113. package/src/templates/skills/agentkit-database/templates/appointments.schema.sql +15 -0
  114. package/src/templates/skills/agentkit-database/templates/leads.schema.sql +17 -0
  115. package/src/templates/skills/agentkit-deploy/SKILL.md +50 -0
  116. package/src/templates/skills/agentkit-evals/SKILL.md +109 -0
  117. package/src/templates/skills/agentkit-evals/templates/multi-turn.eval.md +29 -0
  118. package/src/templates/skills/agentkit-evals/templates/no-leak.eval.md +18 -0
  119. package/src/templates/skills/agentkit-evals/templates/smoke.eval.md +18 -0
  120. package/src/templates/skills/agentkit-evals/templates/tool-call.eval.md +27 -0
  121. package/src/templates/skills/agentkit-improve/SKILL.md +86 -0
  122. package/src/templates/skills/agentkit-improve/references/replay-side-effects.md +18 -0
  123. package/src/templates/skills/agentkit-improve/references/trace-packets.md +22 -0
  124. package/src/templates/skills/agentkit-improve/templates/regression.eval.md +18 -0
  125. package/src/templates/skills/agentkit-integrations/SKILL.md +76 -0
  126. package/src/templates/skills/agentkit-knowledge/SKILL.md +43 -0
  127. package/src/templates/skills/agentkit-knowledge/templates/faq.md +14 -0
  128. package/src/templates/skills/agentkit-knowledge/templates/policies.md +14 -0
  129. package/src/templates/skills/agentkit-knowledge/templates/prices.csv +3 -0
  130. package/src/templates/skills/agentkit-prompts/SKILL.md +47 -0
  131. package/src/templates/skills/agentkit-prompts/templates/knowledge-grounded-faq.instructions.md +11 -0
  132. package/src/templates/skills/agentkit-provider/SKILL.md +60 -0
  133. package/src/templates/skills/agentkit-security/SKILL.md +56 -0
  134. package/src/templates/skills/agentkit-tools/SKILL.md +37 -0
  135. package/src/templates/skills/agentkit-tools/examples/database-write.tool.md +35 -0
  136. package/src/templates/skills/agentkit-tools/examples/eval-safe-external-action.tool.md +37 -0
  137. package/src/templates/skills/agentkit-tools/examples/lookup-order.tool.md +46 -0
  138. package/src/templates/skills/agentkit-troubleshooting/SKILL.md +76 -0
  139. package/src/templates/support.ts +77 -18
  140. package/docs/guides/channels-production-handoff.md +0 -99
  141. package/docs/portable-deploy-release-checklist.md +0 -41
  142. package/src/runtime/targets/cloudflare/deploy.ts +0 -5475
@@ -12,7 +12,7 @@ export async function startContainerRuntime(options: ContainerRuntimeOptions = {
12
12
  const capsuleRoot = resolve(options.capsuleRoot ?? process.env.AGENTKIT_CAPSULE_ROOT ?? process.cwd());
13
13
  const hostname = options.hostname ?? process.env.HOST ?? "0.0.0.0";
14
14
  const port = options.port ?? parsePort(process.env.PORT) ?? 4123;
15
- return startAgentDevServer(capsuleRoot, { hostname, port });
15
+ return startAgentDevServer(capsuleRoot, { hostname, port, access: "enforce" });
16
16
  }
17
17
 
18
18
  function parsePort(value: string | undefined): number | undefined {
@@ -1,4 +1,4 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
1
+ import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
 
4
4
  import type { LocalDeployState } from "../../core/deploy-state";
@@ -38,15 +38,19 @@ export async function prepareVpsDeploy(
38
38
  const manifest = JSON.parse(await readFile(container.manifestPath, "utf8")) as {
39
39
  name: string;
40
40
  secrets: string[];
41
+ access: {
42
+ mode: "private" | "token" | "public";
43
+ };
41
44
  };
42
45
 
43
46
  await mkdir(buildDir, { recursive: true });
44
47
  const envExample = renderEnvExample(manifest.secrets);
45
48
  await writeFile(composePath, renderCompose(manifest.name));
46
49
  await writeFile(envExamplePath, envExample);
47
- await writeFile(envPath, envExample);
50
+ await writeFile(envPath, envExample, { mode: 0o600 });
51
+ await chmod(envPath, 0o600);
48
52
  await writeFile(secretsPath, renderSecretsChecklist(manifest.secrets));
49
- await writeFile(handoffPath, renderProductionHandoff(options.host, manifest.name));
53
+ await writeFile(handoffPath, renderProductionHandoff(options.host, manifest.name, manifest.access.mode));
50
54
 
51
55
  const state: LocalDeployState = {
52
56
  deploy_id: `vps_${slugify(manifest.name)}`,
@@ -71,7 +75,8 @@ export async function prepareVpsDeploy(
71
75
  },
72
76
  created_at: new Date().toISOString(),
73
77
  };
74
- await writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`);
78
+ await writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 });
79
+ await chmod(statePath, 0o600);
75
80
 
76
81
  return {
77
82
  target: "vps",
@@ -88,7 +93,7 @@ export async function prepareVpsDeploy(
88
93
  `docker compose -f ${composePath} --env-file ${envPath} config`,
89
94
  `docker compose -f ${composePath} --env-file ${envPath} up -d --build`,
90
95
  `curl -fsS https://${options.host}/health`,
91
- `curl -fsS https://${options.host}/_agentkit`,
96
+ `curl -fsS -H "Authorization: Bearer $AGENTKIT_PRIVATE_TOKEN" https://${options.host}/_agentkit`,
92
97
  ],
93
98
  };
94
99
  }
@@ -113,7 +118,7 @@ function renderCompose(agentName: string): string {
113
118
  - agentkit_data:/data
114
119
  - agentkit_files:/capsule/.agentkit/files
115
120
  healthcheck:
116
- test: ["CMD", "bun", "-e", "const r=await fetch('http://127.0.0.1:4123/health'); process.exit(r.ok?0:1)"]
121
+ test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:4123/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
117
122
  interval: 30s
118
123
  timeout: 5s
119
124
  retries: 3
@@ -145,7 +150,7 @@ ${lines}
145
150
  `;
146
151
  }
147
152
 
148
- function renderProductionHandoff(host: string, agentName: string): string {
153
+ function renderProductionHandoff(host: string, agentName: string, accessMode: "private" | "token" | "public"): string {
149
154
  return `# VPS Production Handoff
150
155
 
151
156
  ## Deploy
@@ -169,12 +174,14 @@ docker compose -f .agentkit/build/vps/compose.yaml --env-file .agentkit/build/vp
169
174
 
170
175
  \`\`\`sh
171
176
  curl -fsS https://${host}/health
172
- curl -fsS https://${host}/_agentkit
177
+ curl -fsS -H "Authorization: Bearer $AGENTKIT_PRIVATE_TOKEN" https://${host}/_agentkit
173
178
  curl -fsS -X POST https://${host}/chat \\
174
- -H 'content-type: application/json' \\
179
+ -H 'content-type: application/json'${renderChatAuthHeader(accessMode)} \\
175
180
  -d '{"message":{"role":"user","content":"hello"}}'
176
181
  \`\`\`
177
182
 
183
+ Set AGENTKIT_PRIVATE_TOKEN for privileged AgentKit endpoints. Chat access follows access.mode: ${accessMode}.
184
+
178
185
  ## Database
179
186
 
180
187
  - Default database: SQLite at /data/agentkit.db in the agentkit_data volume.
@@ -195,6 +202,16 @@ docker compose -f .agentkit/build/vps/compose.yaml --env-file .agentkit/build/vp
195
202
  `;
196
203
  }
197
204
 
205
+ function renderChatAuthHeader(accessMode: "private" | "token" | "public"): string {
206
+ if (accessMode === "public") {
207
+ return "";
208
+ }
209
+
210
+ const secretName = accessMode === "private" ? "AGENTKIT_PRIVATE_TOKEN" : "AGENTKIT_ACCESS_TOKEN";
211
+ return ` \\
212
+ -H "Authorization: Bearer $${secretName}"`;
213
+ }
214
+
198
215
  function slugify(value: string): string {
199
216
  const slug = value
200
217
  .toLowerCase()
@@ -2,12 +2,15 @@ import { loadAgentCapsule } from "./config";
2
2
  import { openPreparedCapsuleStore } from "./database";
3
3
  import { loadCapsuleEnv } from "./env";
4
4
  import { isAgentKitError } from "./errors";
5
+ import { createManagedComposioTools } from "./integrations/composio";
6
+ import { buildRuntimeClockContext } from "./prompt-context";
5
7
  import { createToolRuntime, type ToolCallResult } from "./tools";
6
8
 
7
9
  export type RunToolOptions = {
8
10
  name: string;
9
11
  input?: unknown;
10
12
  signal?: AbortSignal;
13
+ now?: Date;
11
14
  };
12
15
 
13
16
  export async function runToolFromCwd(cwd: string, options: RunToolOptions): Promise<ToolCallResult> {
@@ -24,12 +27,17 @@ export async function runToolFromCwd(cwd: string, options: RunToolOptions): Prom
24
27
  model: capsule.config.provider.model,
25
28
  });
26
29
  const toolRuntime = createToolRuntime({
27
- tools: capsule.config.tools ?? [],
30
+ tools: [...createManagedComposioTools(capsule.config), ...(capsule.config.tools ?? [])],
28
31
  store,
29
32
  runId: run.id,
30
33
  conversationId: conversation.id,
31
34
  env,
32
35
  signal: options.signal,
36
+ clock: buildRuntimeClockContext({
37
+ timeZone: capsule.config.timeZone,
38
+ env,
39
+ now: options.now,
40
+ }),
33
41
  runtime: {
34
42
  environment: "local",
35
43
  invocation: "tool",
@@ -1,7 +1,8 @@
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";
5
+ import type { RuntimeClockContext } from "./prompt-context";
5
6
 
6
7
  export type ToolCallRequest = {
7
8
  name: string;
@@ -14,6 +15,7 @@ export type ToolCallResult = {
14
15
  visibility: "user" | "internal";
15
16
  input: unknown;
16
17
  output: unknown;
18
+ rendered?: ToolRenderResult;
17
19
  };
18
20
 
19
21
  export type ToolRuntime = {
@@ -30,6 +32,7 @@ export type ToolRuntimeOptions = {
30
32
  signal?: AbortSignal;
31
33
  defaultTimeoutMs?: number;
32
34
  runtime: ToolRuntimeContext;
35
+ clock: RuntimeClockContext;
33
36
  };
34
37
 
35
38
  const DEFAULT_TOOL_TIMEOUT_MS = 30_000;
@@ -88,6 +91,7 @@ async function executeToolCall(
88
91
  secrets,
89
92
  database,
90
93
  runtime: options.runtime,
94
+ clock: options.clock,
91
95
  signal: options.signal,
92
96
  },
93
97
  tool.timeoutMs ?? options.defaultTimeoutMs ?? DEFAULT_TOOL_TIMEOUT_MS,
@@ -97,10 +101,13 @@ async function executeToolCall(
97
101
  validateSchema(output, tool.outputSchema, `tool "${tool.name}" output`);
98
102
  }
99
103
 
104
+ const rendered = renderToolOutput(tool, input, output, options.runtime, options.clock);
105
+
100
106
  options.store.completeToolCall({
101
107
  toolCallId: toolCall.id,
102
108
  status: "completed",
103
109
  output,
110
+ rendered,
104
111
  secretValues,
105
112
  });
106
113
 
@@ -110,6 +117,7 @@ async function executeToolCall(
110
117
  visibility: tool.visibility ?? "user",
111
118
  input,
112
119
  output,
120
+ ...(rendered ? { rendered } : {}),
113
121
  };
114
122
  } catch (error) {
115
123
  const secretValues = collectConfiguredSecretValues(tool, options.env ?? process.env);
@@ -125,6 +133,123 @@ async function executeToolCall(
125
133
  }
126
134
  }
127
135
 
136
+ function renderToolOutput(
137
+ tool: AgentTool,
138
+ input: unknown,
139
+ output: unknown,
140
+ runtime: ToolRuntimeContext,
141
+ clock: RuntimeClockContext,
142
+ ): ToolRenderResult | undefined {
143
+ if (!tool.render) {
144
+ return undefined;
145
+ }
146
+
147
+ const rendered = tool.render(output, {
148
+ input,
149
+ runtime,
150
+ clock,
151
+ });
152
+
153
+ if (typeof rendered === "string") {
154
+ return { text: rendered };
155
+ }
156
+
157
+ if (!isRecord(rendered) || typeof rendered.text !== "string" || rendered.text.trim().length === 0) {
158
+ throw new AgentKitError("tool_validation_error", `tool "${tool.name}" render must return a non-empty text string.`);
159
+ }
160
+
161
+ if (rendered.blocks !== undefined) {
162
+ if (!Array.isArray(rendered.blocks)) {
163
+ throw new AgentKitError("tool_validation_error", `tool "${tool.name}" render.blocks must be an array when provided.`);
164
+ }
165
+
166
+ for (const [index, block] of rendered.blocks.entries()) {
167
+ validateRenderBlock(block, `tool "${tool.name}" render.blocks[${index}]`);
168
+ }
169
+ }
170
+
171
+ return {
172
+ text: rendered.text,
173
+ ...(rendered.blocks ? { blocks: rendered.blocks } : {}),
174
+ };
175
+ }
176
+
177
+ function validateRenderBlock(block: unknown, label: string): void {
178
+ if (!isRecord(block)) {
179
+ throw new AgentKitError("tool_validation_error", `${label} must be an object.`);
180
+ }
181
+
182
+ if (block.type === "text") {
183
+ if (typeof block.text !== "string" || block.text.trim().length === 0) {
184
+ throw new AgentKitError("tool_validation_error", `${label}.text must be a non-empty string.`);
185
+ }
186
+ return;
187
+ }
188
+
189
+ if (block.type === "card") {
190
+ if (typeof block.title !== "string" || block.title.trim().length === 0) {
191
+ throw new AgentKitError("tool_validation_error", `${label}.title must be a non-empty string.`);
192
+ }
193
+
194
+ validateOptionalString(block.subtitle, `${label}.subtitle`);
195
+ validateRenderFields(block.fields, `${label}.fields`);
196
+ validateRenderActions(block.actions, `${label}.actions`);
197
+ return;
198
+ }
199
+
200
+ throw new AgentKitError("tool_validation_error", `${label}.type must be "text" or "card".`);
201
+ }
202
+
203
+ function validateRenderFields(value: unknown, label: string): void {
204
+ if (value === undefined) {
205
+ return;
206
+ }
207
+
208
+ if (!Array.isArray(value)) {
209
+ throw new AgentKitError("tool_validation_error", `${label} must be an array when provided.`);
210
+ }
211
+
212
+ for (const [index, field] of value.entries()) {
213
+ if (!isRecord(field)) {
214
+ throw new AgentKitError("tool_validation_error", `${label}[${index}] must be an object.`);
215
+ }
216
+
217
+ validateRequiredString(field.label, `${label}[${index}].label`);
218
+ validateRequiredString(field.value, `${label}[${index}].value`);
219
+ }
220
+ }
221
+
222
+ function validateRenderActions(value: unknown, label: string): void {
223
+ if (value === undefined) {
224
+ return;
225
+ }
226
+
227
+ if (!Array.isArray(value)) {
228
+ throw new AgentKitError("tool_validation_error", `${label} must be an array when provided.`);
229
+ }
230
+
231
+ for (const [index, action] of value.entries()) {
232
+ if (!isRecord(action)) {
233
+ throw new AgentKitError("tool_validation_error", `${label}[${index}] must be an object.`);
234
+ }
235
+
236
+ validateRequiredString(action.label, `${label}[${index}].label`);
237
+ validateOptionalString(action.href, `${label}[${index}].href`);
238
+ }
239
+ }
240
+
241
+ function validateRequiredString(value: unknown, label: string): void {
242
+ if (typeof value !== "string" || value.trim().length === 0) {
243
+ throw new AgentKitError("tool_validation_error", `${label} must be a non-empty string.`);
244
+ }
245
+ }
246
+
247
+ function validateOptionalString(value: unknown, label: string): void {
248
+ if (value !== undefined && typeof value !== "string") {
249
+ throw new AgentKitError("tool_validation_error", `${label} must be a string when provided.`);
250
+ }
251
+ }
252
+
128
253
  function resolveToolSecrets(
129
254
  tool: AgentTool,
130
255
  env: Record<string, string | undefined>,
@@ -158,7 +283,7 @@ function collectConfiguredSecretValues(tool: AgentTool | undefined, env: Record<
158
283
  async function runToolWithTimeout(
159
284
  tool: AgentTool,
160
285
  input: unknown,
161
- context: Pick<ToolContext, "secrets" | "database" | "runtime"> & { signal?: AbortSignal },
286
+ context: Pick<ToolContext, "secrets" | "database" | "runtime" | "clock"> & { signal?: AbortSignal },
162
287
  timeoutMs: number,
163
288
  ): Promise<unknown> {
164
289
  const controller = new AbortController();
@@ -186,6 +311,7 @@ async function runToolWithTimeout(
186
311
  secrets: context.secrets,
187
312
  signal: controller.signal,
188
313
  runtime: context.runtime,
314
+ clock: context.clock,
189
315
  database: context.database,
190
316
  db: context.database,
191
317
  storage: {
@@ -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
+ }