@lakitu/sdk 0.1.0
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 +166 -0
- package/convex/_generated/api.d.ts +45 -0
- package/convex/_generated/api.js +23 -0
- package/convex/_generated/dataModel.d.ts +58 -0
- package/convex/_generated/server.d.ts +143 -0
- package/convex/_generated/server.js +93 -0
- package/convex/cloud/CLAUDE.md +238 -0
- package/convex/cloud/_generated/api.ts +84 -0
- package/convex/cloud/_generated/component.ts +861 -0
- package/convex/cloud/_generated/dataModel.ts +60 -0
- package/convex/cloud/_generated/server.ts +156 -0
- package/convex/cloud/convex.config.ts +16 -0
- package/convex/cloud/index.ts +29 -0
- package/convex/cloud/intentSchema/generate.ts +447 -0
- package/convex/cloud/intentSchema/index.ts +16 -0
- package/convex/cloud/intentSchema/types.ts +418 -0
- package/convex/cloud/ksaPolicy.ts +554 -0
- package/convex/cloud/mail.ts +92 -0
- package/convex/cloud/schema.ts +322 -0
- package/convex/cloud/utils/kanbanContext.ts +229 -0
- package/convex/cloud/workflows/agentBoard.ts +451 -0
- package/convex/cloud/workflows/agentPrompt.ts +272 -0
- package/convex/cloud/workflows/agentThread.ts +374 -0
- package/convex/cloud/workflows/compileSandbox.ts +146 -0
- package/convex/cloud/workflows/crudBoard.ts +217 -0
- package/convex/cloud/workflows/crudKSAs.ts +262 -0
- package/convex/cloud/workflows/crudLorobeads.ts +371 -0
- package/convex/cloud/workflows/crudSkills.ts +205 -0
- package/convex/cloud/workflows/crudThreads.ts +708 -0
- package/convex/cloud/workflows/lifecycleSandbox.ts +1396 -0
- package/convex/cloud/workflows/sandboxConvex.ts +1046 -0
- package/convex/sandbox/README.md +90 -0
- package/convex/sandbox/_generated/api.d.ts +2934 -0
- package/convex/sandbox/_generated/api.js +23 -0
- package/convex/sandbox/_generated/dataModel.d.ts +60 -0
- package/convex/sandbox/_generated/server.d.ts +143 -0
- package/convex/sandbox/_generated/server.js +93 -0
- package/convex/sandbox/actions/bash.ts +130 -0
- package/convex/sandbox/actions/browser.ts +282 -0
- package/convex/sandbox/actions/file.ts +336 -0
- package/convex/sandbox/actions/lsp.ts +325 -0
- package/convex/sandbox/actions/pdf.ts +119 -0
- package/convex/sandbox/agent/codeExecLoop.ts +535 -0
- package/convex/sandbox/agent/decisions.ts +284 -0
- package/convex/sandbox/agent/index.ts +515 -0
- package/convex/sandbox/agent/subagents.ts +651 -0
- package/convex/sandbox/brandResearch/index.ts +417 -0
- package/convex/sandbox/context/index.ts +7 -0
- package/convex/sandbox/context/session.ts +402 -0
- package/convex/sandbox/convex.config.ts +17 -0
- package/convex/sandbox/index.ts +51 -0
- package/convex/sandbox/nodeActions/codeExec.ts +130 -0
- package/convex/sandbox/planning/beads.ts +187 -0
- package/convex/sandbox/planning/index.ts +8 -0
- package/convex/sandbox/planning/sync.ts +194 -0
- package/convex/sandbox/prompts/codeExec.ts +852 -0
- package/convex/sandbox/prompts/modes.ts +231 -0
- package/convex/sandbox/prompts/system.ts +142 -0
- package/convex/sandbox/schema.ts +510 -0
- package/convex/sandbox/state/artifacts.ts +99 -0
- package/convex/sandbox/state/checkpoints.ts +341 -0
- package/convex/sandbox/state/files.ts +383 -0
- package/convex/sandbox/state/index.ts +10 -0
- package/convex/sandbox/state/verification.actions.ts +268 -0
- package/convex/sandbox/state/verification.ts +101 -0
- package/convex/sandbox/tsconfig.json +25 -0
- package/convex/sandbox/utils/codeExecHelpers.ts +52 -0
- package/dist/cli/commands/build.d.ts +19 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +223 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +148 -0
- package/dist/cli/commands/publish.d.ts +12 -0
- package/dist/cli/commands/publish.d.ts.map +1 -0
- package/dist/cli/commands/publish.js +33 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +40 -0
- package/dist/sdk/builders.d.ts +104 -0
- package/dist/sdk/builders.d.ts.map +1 -0
- package/dist/sdk/builders.js +214 -0
- package/dist/sdk/index.d.ts +29 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +38 -0
- package/dist/sdk/types.d.ts +107 -0
- package/dist/sdk/types.d.ts.map +1 -0
- package/dist/sdk/types.js +6 -0
- package/ksa/README.md +263 -0
- package/ksa/_generated/REFERENCE.md +2954 -0
- package/ksa/_generated/registry.ts +257 -0
- package/ksa/_shared/configReader.ts +302 -0
- package/ksa/_shared/configSchemas.ts +649 -0
- package/ksa/_shared/gateway.ts +175 -0
- package/ksa/_shared/ksaBehaviors.ts +411 -0
- package/ksa/_shared/ksaProxy.ts +248 -0
- package/ksa/_shared/localDb.ts +302 -0
- package/ksa/index.ts +134 -0
- package/package.json +93 -0
- package/runtime/browser/agent-browser.ts +330 -0
- package/runtime/entrypoint.ts +194 -0
- package/runtime/lsp/manager.ts +366 -0
- package/runtime/pdf/pdf-generator.ts +50 -0
- package/runtime/pdf/renderer.ts +357 -0
- package/runtime/pdf/schema.ts +97 -0
- package/runtime/services/file-watcher.ts +191 -0
- package/template/build.ts +307 -0
- package/template/e2b/Dockerfile +69 -0
- package/template/e2b/e2b.toml +13 -0
- package/template/e2b/prebuild.sh +68 -0
- package/template/e2b/start.sh +14 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lakitu Cloud Component Schema
|
|
3
|
+
*
|
|
4
|
+
* Tables for agent sessions, threads, skills, and sandbox management.
|
|
5
|
+
* This is a Convex component schema - tables are isolated from the main app.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { defineSchema, defineTable } from "convex/server";
|
|
9
|
+
import { v } from "convex/values";
|
|
10
|
+
|
|
11
|
+
export default defineSchema({
|
|
12
|
+
// Session management
|
|
13
|
+
agentSessions: defineTable({
|
|
14
|
+
projectId: v.string(),
|
|
15
|
+
status: v.union(
|
|
16
|
+
v.literal("pending"),
|
|
17
|
+
v.literal("running"),
|
|
18
|
+
v.literal("completed"),
|
|
19
|
+
v.literal("failed"),
|
|
20
|
+
v.literal("cancelled")
|
|
21
|
+
),
|
|
22
|
+
sandboxId: v.optional(v.string()),
|
|
23
|
+
sandboxHost: v.optional(v.string()), // e2b public host URL for direct HTTP
|
|
24
|
+
openCodeSessionId: v.optional(v.string()), // OpenCode session ID for polling
|
|
25
|
+
config: v.optional(v.any()),
|
|
26
|
+
secret: v.optional(v.string()),
|
|
27
|
+
output: v.optional(v.any()),
|
|
28
|
+
error: v.optional(v.string()),
|
|
29
|
+
logs: v.optional(v.array(v.string())),
|
|
30
|
+
lastHeartbeat: v.optional(v.number()),
|
|
31
|
+
createdAt: v.number(),
|
|
32
|
+
updatedAt: v.number(),
|
|
33
|
+
completedAt: v.optional(v.number()),
|
|
34
|
+
})
|
|
35
|
+
.index("by_project", ["projectId"])
|
|
36
|
+
.index("by_sandbox", ["sandboxId"])
|
|
37
|
+
.index("by_status", ["status"]),
|
|
38
|
+
|
|
39
|
+
// Session logs (separated for high-concurrency writes)
|
|
40
|
+
agentSessionLogs: defineTable({
|
|
41
|
+
sessionId: v.id("agentSessions"),
|
|
42
|
+
message: v.string(),
|
|
43
|
+
createdAt: v.number(),
|
|
44
|
+
}).index("by_session", ["sessionId"]),
|
|
45
|
+
|
|
46
|
+
// Beads Issues (separated for high-concurrency writes)
|
|
47
|
+
beadsIssues: defineTable({
|
|
48
|
+
cardId: v.string(), // ID from parent app's cards table
|
|
49
|
+
beadsId: v.string(),
|
|
50
|
+
title: v.string(),
|
|
51
|
+
type: v.string(),
|
|
52
|
+
status: v.string(),
|
|
53
|
+
parent: v.optional(v.string()),
|
|
54
|
+
blocks: v.optional(v.array(v.string())),
|
|
55
|
+
metadata: v.optional(v.any()),
|
|
56
|
+
updatedAt: v.number(),
|
|
57
|
+
})
|
|
58
|
+
.index("by_card", ["cardId"])
|
|
59
|
+
.index("by_beadsId", ["beadsId"])
|
|
60
|
+
.index("by_card_beads", ["cardId", "beadsId"]),
|
|
61
|
+
|
|
62
|
+
// Project-level conversations (for workflows)
|
|
63
|
+
agentConversations: defineTable({
|
|
64
|
+
projectId: v.string(),
|
|
65
|
+
messages: v.array(v.object({
|
|
66
|
+
role: v.union(v.literal("user"), v.literal("assistant")),
|
|
67
|
+
content: v.string(),
|
|
68
|
+
timestamp: v.number(),
|
|
69
|
+
metadata: v.optional(v.any()),
|
|
70
|
+
})),
|
|
71
|
+
createdAt: v.number(),
|
|
72
|
+
updatedAt: v.number(),
|
|
73
|
+
}).index("by_project", ["projectId"]),
|
|
74
|
+
|
|
75
|
+
// Chat threads
|
|
76
|
+
threads: defineTable({
|
|
77
|
+
userId: v.string(),
|
|
78
|
+
orgId: v.optional(v.string()),
|
|
79
|
+
boardId: v.optional(v.string()),
|
|
80
|
+
workspaceId: v.optional(v.string()), // Workspace-scoped threads
|
|
81
|
+
title: v.string(),
|
|
82
|
+
createdAt: v.number(),
|
|
83
|
+
updatedAt: v.number(),
|
|
84
|
+
})
|
|
85
|
+
.index("by_user", ["userId"])
|
|
86
|
+
.index("by_org", ["orgId"])
|
|
87
|
+
.index("by_workspace", ["workspaceId"]),
|
|
88
|
+
|
|
89
|
+
// Thread messages
|
|
90
|
+
threadMessages: defineTable({
|
|
91
|
+
threadId: v.id("threads"),
|
|
92
|
+
role: v.union(v.literal("user"), v.literal("assistant")),
|
|
93
|
+
content: v.string(),
|
|
94
|
+
createdAt: v.number(),
|
|
95
|
+
// Metadata for special message types
|
|
96
|
+
metadata: v.optional(v.object({
|
|
97
|
+
type: v.optional(v.union(
|
|
98
|
+
v.literal("text"),
|
|
99
|
+
v.literal("subagent"),
|
|
100
|
+
v.literal("board_execution"),
|
|
101
|
+
v.literal("frame_preview"),
|
|
102
|
+
v.literal("artifact"),
|
|
103
|
+
v.literal("session_logs")
|
|
104
|
+
)),
|
|
105
|
+
data: v.optional(v.any()),
|
|
106
|
+
// Persisted session logs (CoT) for historical display
|
|
107
|
+
sessionLogs: v.optional(v.object({
|
|
108
|
+
logs: v.array(v.object({
|
|
109
|
+
type: v.string(),
|
|
110
|
+
label: v.string(),
|
|
111
|
+
status: v.optional(v.string()),
|
|
112
|
+
details: v.optional(v.string()),
|
|
113
|
+
data: v.optional(v.any()),
|
|
114
|
+
})),
|
|
115
|
+
status: v.string(),
|
|
116
|
+
})),
|
|
117
|
+
// Generation time in milliseconds
|
|
118
|
+
generationTime: v.optional(v.number()),
|
|
119
|
+
// Chain of thought steps
|
|
120
|
+
thinking: v.optional(v.any()),
|
|
121
|
+
})),
|
|
122
|
+
}).index("by_thread", ["threadId"]),
|
|
123
|
+
|
|
124
|
+
// Thread artifacts (for agent chat threads, similar to kanban artifacts)
|
|
125
|
+
threadArtifacts: defineTable({
|
|
126
|
+
threadId: v.id("threads"),
|
|
127
|
+
sessionId: v.optional(v.id("convexSandboxSessions")),
|
|
128
|
+
type: v.string(), // markdown, json, csv, text, html, pdf
|
|
129
|
+
name: v.string(),
|
|
130
|
+
content: v.string(),
|
|
131
|
+
r2Key: v.optional(v.string()), // R2 backup key
|
|
132
|
+
metadata: v.optional(v.any()),
|
|
133
|
+
createdAt: v.number(),
|
|
134
|
+
})
|
|
135
|
+
.index("by_thread", ["threadId"])
|
|
136
|
+
.index("by_session", ["sessionId"]),
|
|
137
|
+
|
|
138
|
+
// Skill definitions
|
|
139
|
+
skills: defineTable({
|
|
140
|
+
skillId: v.string(),
|
|
141
|
+
name: v.string(),
|
|
142
|
+
description: v.string(),
|
|
143
|
+
icon: v.string(),
|
|
144
|
+
category: v.string(),
|
|
145
|
+
toolIds: v.array(v.string()),
|
|
146
|
+
prompt: v.optional(v.string()),
|
|
147
|
+
configSchema: v.optional(v.any()),
|
|
148
|
+
defaults: v.optional(v.any()),
|
|
149
|
+
isBuiltIn: v.boolean(),
|
|
150
|
+
userId: v.optional(v.string()),
|
|
151
|
+
orgId: v.optional(v.string()),
|
|
152
|
+
createdAt: v.number(),
|
|
153
|
+
})
|
|
154
|
+
.index("by_skillId", ["skillId"])
|
|
155
|
+
.index("by_builtin", ["isBuiltIn"])
|
|
156
|
+
.index("by_user", ["userId"]),
|
|
157
|
+
|
|
158
|
+
// Beads/Loro snapshots
|
|
159
|
+
beadsSnapshots: defineTable({
|
|
160
|
+
cardId: v.string(), // ID from parent app's cards table
|
|
161
|
+
runId: v.optional(v.string()), // ID from parent app's cardRuns table
|
|
162
|
+
loroSnapshot: v.optional(v.bytes()),
|
|
163
|
+
beadsState: v.string(),
|
|
164
|
+
vfsManifest: v.array(v.object({
|
|
165
|
+
path: v.string(),
|
|
166
|
+
r2Key: v.string(),
|
|
167
|
+
size: v.number(),
|
|
168
|
+
type: v.string(),
|
|
169
|
+
})),
|
|
170
|
+
gitCommit: v.optional(v.string()),
|
|
171
|
+
createdAt: v.number(),
|
|
172
|
+
})
|
|
173
|
+
.index("by_card", ["cardId"])
|
|
174
|
+
.index("by_run", ["runId"]),
|
|
175
|
+
|
|
176
|
+
// Beads Loro CRDT updates
|
|
177
|
+
beadsLoroUpdates: defineTable({
|
|
178
|
+
cardId: v.string(), // ID from parent app's cards table
|
|
179
|
+
updateBytes: v.bytes(),
|
|
180
|
+
clientId: v.string(),
|
|
181
|
+
createdAt: v.number(),
|
|
182
|
+
}).index("by_card_time", ["cardId", "createdAt"]),
|
|
183
|
+
|
|
184
|
+
// Multi-agent mail coordination
|
|
185
|
+
agentMail: defineTable({
|
|
186
|
+
senderId: v.string(),
|
|
187
|
+
recipientId: v.string(),
|
|
188
|
+
messageType: v.string(),
|
|
189
|
+
payload: v.any(),
|
|
190
|
+
read: v.optional(v.boolean()),
|
|
191
|
+
status: v.optional(v.string()),
|
|
192
|
+
expiresAt: v.optional(v.number()),
|
|
193
|
+
createdAt: v.number(),
|
|
194
|
+
})
|
|
195
|
+
.index("by_recipient", ["recipientId"])
|
|
196
|
+
.index("by_sender", ["senderId"]),
|
|
197
|
+
|
|
198
|
+
// UI context for agent interactions
|
|
199
|
+
agentContexts: defineTable({
|
|
200
|
+
userId: v.string(),
|
|
201
|
+
context: v.any(),
|
|
202
|
+
updatedAt: v.number(),
|
|
203
|
+
}).index("by_user", ["userId"]),
|
|
204
|
+
|
|
205
|
+
// Custom tool definitions (user/vendor/integration extensible)
|
|
206
|
+
customTools: defineTable({
|
|
207
|
+
toolId: v.string(),
|
|
208
|
+
name: v.string(),
|
|
209
|
+
description: v.string(),
|
|
210
|
+
category: v.union(
|
|
211
|
+
v.literal("core"),
|
|
212
|
+
v.literal("research"),
|
|
213
|
+
v.literal("content"),
|
|
214
|
+
v.literal("workflow"),
|
|
215
|
+
v.literal("integration")
|
|
216
|
+
),
|
|
217
|
+
exports: v.array(v.object({
|
|
218
|
+
name: v.string(),
|
|
219
|
+
description: v.string(),
|
|
220
|
+
})),
|
|
221
|
+
implementation: v.string(), // TypeScript code
|
|
222
|
+
isBuiltIn: v.boolean(),
|
|
223
|
+
userId: v.optional(v.string()),
|
|
224
|
+
orgId: v.optional(v.string()),
|
|
225
|
+
vendorId: v.optional(v.string()),
|
|
226
|
+
enabled: v.boolean(),
|
|
227
|
+
createdAt: v.number(),
|
|
228
|
+
updatedAt: v.number(),
|
|
229
|
+
})
|
|
230
|
+
.index("by_toolId", ["toolId"])
|
|
231
|
+
.index("by_builtin", ["isBuiltIn"])
|
|
232
|
+
.index("by_user", ["userId"])
|
|
233
|
+
.index("by_org", ["orgId"])
|
|
234
|
+
.index("by_vendor", ["vendorId"]),
|
|
235
|
+
|
|
236
|
+
// Compiled sandbox files stored in R2
|
|
237
|
+
compiledSandbox: defineTable({
|
|
238
|
+
version: v.string(), // Semantic version or timestamp
|
|
239
|
+
type: v.union(v.literal("tool"), v.literal("skill"), v.literal("agent"), v.literal("service")),
|
|
240
|
+
name: v.string(), // e.g., "web", "research", "automator"
|
|
241
|
+
r2Key: v.string(), // R2 storage key
|
|
242
|
+
contentHash: v.string(), // For cache invalidation
|
|
243
|
+
metadata: v.optional(v.any()),
|
|
244
|
+
createdAt: v.number(),
|
|
245
|
+
})
|
|
246
|
+
.index("by_type_name", ["type", "name"])
|
|
247
|
+
.index("by_version", ["version"]),
|
|
248
|
+
|
|
249
|
+
// ============================================
|
|
250
|
+
// Convex Sandbox Sessions (new architecture)
|
|
251
|
+
// Self-hosted Convex in E2B with Agent SDK
|
|
252
|
+
// ============================================
|
|
253
|
+
|
|
254
|
+
convexSandboxSessions: defineTable({
|
|
255
|
+
projectId: v.string(),
|
|
256
|
+
prompt: v.string(),
|
|
257
|
+
status: v.union(
|
|
258
|
+
v.literal("pending"),
|
|
259
|
+
v.literal("starting"),
|
|
260
|
+
v.literal("running"),
|
|
261
|
+
v.literal("completed"),
|
|
262
|
+
v.literal("failed"),
|
|
263
|
+
v.literal("cancelled"),
|
|
264
|
+
v.literal("checkpointed")
|
|
265
|
+
),
|
|
266
|
+
config: v.optional(v.any()),
|
|
267
|
+
// Sandbox info
|
|
268
|
+
sandboxId: v.optional(v.string()),
|
|
269
|
+
sandboxUrl: v.optional(v.string()),
|
|
270
|
+
// Agent thread in sandbox Convex
|
|
271
|
+
threadId: v.optional(v.string()),
|
|
272
|
+
// Results
|
|
273
|
+
output: v.optional(v.any()),
|
|
274
|
+
error: v.optional(v.string()),
|
|
275
|
+
// Checkpointing for chained runs
|
|
276
|
+
checkpointId: v.optional(v.string()),
|
|
277
|
+
iteration: v.number(),
|
|
278
|
+
// Metrics
|
|
279
|
+
metrics: v.optional(v.any()),
|
|
280
|
+
// Timestamps
|
|
281
|
+
createdAt: v.number(),
|
|
282
|
+
updatedAt: v.number(),
|
|
283
|
+
completedAt: v.optional(v.number()),
|
|
284
|
+
})
|
|
285
|
+
.index("by_project", ["projectId"])
|
|
286
|
+
.index("by_status", ["status"])
|
|
287
|
+
.index("by_sandbox", ["sandboxId"]),
|
|
288
|
+
|
|
289
|
+
// Convex sandbox session logs
|
|
290
|
+
convexSandboxLogs: defineTable({
|
|
291
|
+
sessionId: v.id("convexSandboxSessions"),
|
|
292
|
+
message: v.string(), // Plain text or JSON-stringified structured log
|
|
293
|
+
level: v.union(v.literal("info"), v.literal("warn"), v.literal("error")),
|
|
294
|
+
timestamp: v.number(),
|
|
295
|
+
// Structured log fields (optional)
|
|
296
|
+
stepType: v.optional(v.string()), // thinking, tool, search, file, text
|
|
297
|
+
}).index("by_session", ["sessionId"]),
|
|
298
|
+
|
|
299
|
+
// ============================================
|
|
300
|
+
// Warm Sandbox Pool
|
|
301
|
+
// Pre-warmed E2B sandboxes for fast startup
|
|
302
|
+
// ============================================
|
|
303
|
+
|
|
304
|
+
sandboxPool: defineTable({
|
|
305
|
+
sandboxId: v.string(),
|
|
306
|
+
sandboxUrl: v.string(),
|
|
307
|
+
sandboxHost: v.string(),
|
|
308
|
+
status: v.union(
|
|
309
|
+
v.literal("warming"), // Being created
|
|
310
|
+
v.literal("ready"), // Available for claiming
|
|
311
|
+
v.literal("claimed"), // In use
|
|
312
|
+
v.literal("expired"), // Past TTL, needs cleanup
|
|
313
|
+
),
|
|
314
|
+
createdAt: v.number(),
|
|
315
|
+
readyAt: v.optional(v.number()),
|
|
316
|
+
expiresAt: v.number(), // createdAt + TTL (8 min)
|
|
317
|
+
claimedAt: v.optional(v.number()),
|
|
318
|
+
claimedBy: v.optional(v.string()), // sessionId
|
|
319
|
+
})
|
|
320
|
+
.index("by_status", ["status"])
|
|
321
|
+
.index("by_expires", ["expiresAt"]),
|
|
322
|
+
});
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kanban Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds system prompts for the Kanban agent.
|
|
5
|
+
* Uses plain types to work with data from parent app.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Plain types that match parent app's data structures
|
|
9
|
+
interface Board {
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface BoardTask {
|
|
14
|
+
_id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
automation?: { prompt?: string };
|
|
17
|
+
agentPrompt?: string;
|
|
18
|
+
goals?: Array<{ text?: string }>;
|
|
19
|
+
skills?: Array<{ id: string }>;
|
|
20
|
+
deliverables?: Array<{ name: string; type: string }>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface Card {
|
|
24
|
+
name: string;
|
|
25
|
+
context?: {
|
|
26
|
+
variables?: { message?: string };
|
|
27
|
+
artifacts?: Array<{ name: string; type: string; id: string }>;
|
|
28
|
+
};
|
|
29
|
+
history?: Array<{
|
|
30
|
+
taskId: string;
|
|
31
|
+
taskName: string;
|
|
32
|
+
summary?: string;
|
|
33
|
+
files?: Array<{ name: string }>;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Builds a CONCISE system prompt for the Kanban agent.
|
|
39
|
+
* Optimized for minimal tokens while preserving essential context.
|
|
40
|
+
*/
|
|
41
|
+
export function buildSystemPrompt(
|
|
42
|
+
board: Board,
|
|
43
|
+
task: BoardTask,
|
|
44
|
+
card: Card,
|
|
45
|
+
allTasks?: BoardTask[]
|
|
46
|
+
) {
|
|
47
|
+
const pipeline = buildPipelineOverview(task, allTasks);
|
|
48
|
+
const previousWork = buildPreviousStageSummaries(card);
|
|
49
|
+
const artifacts = buildArtifactsList(card);
|
|
50
|
+
const deliverables = buildDeliverablesSection(task);
|
|
51
|
+
const ksas = buildKSAsSection(task);
|
|
52
|
+
|
|
53
|
+
const userMessage = card.context?.variables?.message;
|
|
54
|
+
const messageSection = userMessage ? `User Request: ${userMessage}\n` : "";
|
|
55
|
+
|
|
56
|
+
const hasPreviousWork = (card.history || []).length > 0;
|
|
57
|
+
const continuationGuidance = hasPreviousWork ? `
|
|
58
|
+
## IMPORTANT: This is Stage ${(card.history?.length || 0) + 1} of a Multi-Stage Pipeline
|
|
59
|
+
|
|
60
|
+
You MUST:
|
|
61
|
+
1. First, READ the artifacts from previous stages using \`readArtifact()\`
|
|
62
|
+
2. Use the content from previous stages as INPUT for your work
|
|
63
|
+
3. Do NOT fabricate or make up data - use what was already researched/created
|
|
64
|
+
4. If the previous stage produced research/data, REFERENCE IT in your output
|
|
65
|
+
|
|
66
|
+
` : "";
|
|
67
|
+
|
|
68
|
+
return `# ${task.name}
|
|
69
|
+
${pipeline}
|
|
70
|
+
## Context
|
|
71
|
+
Card: ${card.name}
|
|
72
|
+
Board: ${board.name}
|
|
73
|
+
${messageSection}
|
|
74
|
+
${continuationGuidance}${previousWork}${artifacts}
|
|
75
|
+
## Objective
|
|
76
|
+
${task.automation?.prompt || task.agentPrompt || "Complete this stage."}
|
|
77
|
+
|
|
78
|
+
${buildGoalsSection(task)}
|
|
79
|
+
${deliverables}
|
|
80
|
+
${ksas}
|
|
81
|
+
## Rules
|
|
82
|
+
1. ONLY use KSAs listed above - import and call them in TypeScript code blocks
|
|
83
|
+
2. ${hasPreviousWork ? "**FIRST** read artifacts from previous stages, THEN " : ""}Save deliverables by writing code that calls the appropriate KSA:
|
|
84
|
+
- For PDFs: \`import { generate } from './ksa/pdf'; await generate({ filename, content });\`
|
|
85
|
+
- For markdown: \`import { saveArtifact } from './ksa/artifacts'; await saveArtifact({ name, type: 'markdown', content });\`
|
|
86
|
+
3. Complete ALL steps in this single turn
|
|
87
|
+
4. Respond with a brief summary after all code executes
|
|
88
|
+
${hasPreviousWork ? "5. DO NOT make up information - use data from previous stages" : ""}
|
|
89
|
+
`.trim();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function buildPipelineOverview(currentTask: BoardTask, allTasks?: BoardTask[]) {
|
|
93
|
+
if (!allTasks || allTasks.length <= 1) return "";
|
|
94
|
+
|
|
95
|
+
const idx = allTasks.findIndex(t => t._id === currentTask._id);
|
|
96
|
+
if (idx === -1) return "";
|
|
97
|
+
|
|
98
|
+
const stages = allTasks.map((t, i) =>
|
|
99
|
+
i < idx ? `✓ ${t.name}` : i === idx ? `→ ${t.name}` : `○ ${t.name}`
|
|
100
|
+
).join(" | ");
|
|
101
|
+
|
|
102
|
+
return `Stage ${idx + 1}/${allTasks.length}: ${stages}\n`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function buildArtifactsList(card: Card) {
|
|
106
|
+
const artifacts = card.context?.artifacts || [];
|
|
107
|
+
if (artifacts.length === 0) return "Artifacts: none yet\n";
|
|
108
|
+
|
|
109
|
+
return `## Previous Stage Artifacts (IMPORTANT: READ THESE)
|
|
110
|
+
${artifacts.map((a) => `- ${a.name} (${a.type}, ID: ${a.id})`).join("\n")}
|
|
111
|
+
|
|
112
|
+
**CRITICAL**: Before starting work, you MUST read the artifacts from previous stages.
|
|
113
|
+
Use the artifacts KSA to read them:
|
|
114
|
+
\`\`\`typescript
|
|
115
|
+
import { readArtifact } from './ksa/artifacts';
|
|
116
|
+
const content = await readArtifact('${artifacts[0]?.id || 'artifact-id'}');
|
|
117
|
+
console.log(content); // Use this content as input for your work
|
|
118
|
+
\`\`\`
|
|
119
|
+
`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function buildGoalsSection(task: BoardTask) {
|
|
123
|
+
const goals = task.goals || [];
|
|
124
|
+
const goalTexts = goals.filter((g) => g.text).map((g) => g.text);
|
|
125
|
+
if (goalTexts.length === 0) return "";
|
|
126
|
+
return `## Goals\n${goalTexts.map((t, i) => `${i + 1}. ${t}`).join("\n")}\n`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildKSAsSection(task: BoardTask) {
|
|
130
|
+
const skills = (task.skills || []).map((s) => s.id);
|
|
131
|
+
const deliverables = task.deliverables || [];
|
|
132
|
+
const hasPdf = deliverables.some((d) => d.type === 'pdf');
|
|
133
|
+
const hasResearch = skills.includes('research') || skills.includes('scrape');
|
|
134
|
+
|
|
135
|
+
const ksas: string[] = [
|
|
136
|
+
"### artifacts (./ksa/artifacts)",
|
|
137
|
+
"```typescript",
|
|
138
|
+
"import { saveArtifact, readArtifact, listArtifacts } from './ksa/artifacts';",
|
|
139
|
+
"await saveArtifact({ name: 'report.md', type: 'markdown', content: '...' });",
|
|
140
|
+
"```",
|
|
141
|
+
"",
|
|
142
|
+
"### context (./ksa/context)",
|
|
143
|
+
"```typescript",
|
|
144
|
+
"import { getContext, setVariable } from './ksa/context';",
|
|
145
|
+
"const ctx = await getContext();",
|
|
146
|
+
"await setVariable('key', 'value');",
|
|
147
|
+
"```",
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
if (hasPdf) {
|
|
151
|
+
ksas.push(
|
|
152
|
+
"",
|
|
153
|
+
"### pdf (./ksa/pdf)",
|
|
154
|
+
"```typescript",
|
|
155
|
+
"import { generate } from './ksa/pdf';",
|
|
156
|
+
"await generate({ filename: 'report', content: '# Title\\n...' });",
|
|
157
|
+
"```"
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (hasResearch) {
|
|
162
|
+
ksas.push(
|
|
163
|
+
"",
|
|
164
|
+
"### web (./ksa/web)",
|
|
165
|
+
"```typescript",
|
|
166
|
+
"import { search, scrape, news } from './ksa/web';",
|
|
167
|
+
"const results = await search('query');",
|
|
168
|
+
"const content = await scrape('https://...');",
|
|
169
|
+
"```"
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return `## Available KSAs\n${ksas.join("\n")}`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function buildDeliverablesSection(task: BoardTask) {
|
|
177
|
+
const deliverables = task.deliverables || [];
|
|
178
|
+
if (deliverables.length === 0) return "";
|
|
179
|
+
|
|
180
|
+
const hasPdf = deliverables.some((d) => d.type === 'pdf');
|
|
181
|
+
const count = deliverables.length;
|
|
182
|
+
|
|
183
|
+
const list = deliverables.map((d, i) => {
|
|
184
|
+
const ksa = d.type === 'pdf'
|
|
185
|
+
? `import { generate } from './ksa/pdf'`
|
|
186
|
+
: `import { saveArtifact } from './ksa/artifacts'`;
|
|
187
|
+
return `${i + 1}. [${d.name}] → ${d.type.toUpperCase()} → ${ksa}`;
|
|
188
|
+
}).join("\n");
|
|
189
|
+
|
|
190
|
+
return `## Required Deliverables (EXACTLY ${count})
|
|
191
|
+
${list}
|
|
192
|
+
|
|
193
|
+
Instructions: Write TypeScript code that imports and calls the KSA ONCE per deliverable.
|
|
194
|
+
Use descriptive filenames (not "${deliverables[0]?.name || 'Deliverable Name'}").
|
|
195
|
+
${hasPdf ? 'For PDFs: Content should start with ONE # heading (this becomes the title).' : ''}
|
|
196
|
+
`;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function buildPreviousStageSummaries(card: Card) {
|
|
200
|
+
const history = card.history || [];
|
|
201
|
+
if (history.length === 0) return "";
|
|
202
|
+
|
|
203
|
+
const summaries = history.map((h, i) => {
|
|
204
|
+
const filesProduced = (h.files || []).map((f) => f.name).join(", ");
|
|
205
|
+
return `### ${i + 1}. ${h.taskName}
|
|
206
|
+
**Summary:** ${h.summary || "No summary available"}
|
|
207
|
+
${filesProduced ? `**Files produced:** ${filesProduced}` : ""}`;
|
|
208
|
+
}).join("\n\n");
|
|
209
|
+
|
|
210
|
+
return `## What Has Been Done (Previous Stages)
|
|
211
|
+
|
|
212
|
+
${summaries}
|
|
213
|
+
|
|
214
|
+
**Your job:** Build upon the work above. Do NOT repeat what was already done.
|
|
215
|
+
Read the artifacts from previous stages to understand the context and use their content as input.
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Returns summary of all stages for retrieval.
|
|
221
|
+
*/
|
|
222
|
+
export function getRetrievableStages(card: Card) {
|
|
223
|
+
return (card.history || []).map((h, i) => ({
|
|
224
|
+
index: i,
|
|
225
|
+
taskId: h.taskId,
|
|
226
|
+
taskName: h.taskName,
|
|
227
|
+
summary: h.summary,
|
|
228
|
+
}));
|
|
229
|
+
}
|