( sdk: ISdk, kv: StateKV, provider: MemoryProvider, )
| 16 | Return as JSON: { "narrative": "...", "keyOutcomes": ["..."], "filesAffected": ["..."], "lessons": ["..."] }`; |
| 17 | |
| 18 | export function registerCrystallizeFunction( |
| 19 | sdk: ISdk, |
| 20 | kv: StateKV, |
| 21 | provider: MemoryProvider, |
| 22 | ): void { |
| 23 | sdk.registerFunction("mem::crystallize", |
| 24 | async (data: { |
| 25 | actionIds: string[]; |
| 26 | sessionId?: string; |
| 27 | project?: string; |
| 28 | }) => { |
| 29 | if (!data.actionIds || data.actionIds.length === 0) { |
| 30 | return { success: false, error: "actionIds is required" }; |
| 31 | } |
| 32 | |
| 33 | const actions: Action[] = []; |
| 34 | for (const id of data.actionIds) { |
| 35 | const action = await kv.get<Action>(KV.actions, id); |
| 36 | if (!action) { |
| 37 | return { success: false, error: `action not found: ${id}` }; |
| 38 | } |
| 39 | if (action.status !== "done" && action.status !== "cancelled") { |
| 40 | return { |
| 41 | success: false, |
| 42 | error: `action ${id} has status "${action.status}", expected "done" or "cancelled"`, |
| 43 | }; |
| 44 | } |
| 45 | actions.push(action); |
| 46 | } |
| 47 | |
| 48 | const allEdges = await kv.list<ActionEdge>(KV.actionEdges); |
| 49 | const idSet = new Set(data.actionIds); |
| 50 | const relevantEdges = allEdges.filter( |
| 51 | (e) => idSet.has(e.sourceActionId) || idSet.has(e.targetActionId), |
| 52 | ); |
| 53 | |
| 54 | const prompt = buildChainText(actions, relevantEdges); |
| 55 | |
| 56 | try { |
| 57 | const response = await provider.summarize(CRYSTALLIZE_SYSTEM, prompt); |
| 58 | const digest = parseDigest(response); |
| 59 | |
| 60 | const crystal: Crystal = { |
| 61 | id: generateId("crys"), |
| 62 | narrative: digest.narrative, |
| 63 | keyOutcomes: digest.keyOutcomes, |
| 64 | filesAffected: digest.filesAffected, |
| 65 | lessons: digest.lessons, |
| 66 | sourceActionIds: data.actionIds, |
| 67 | sessionId: data.sessionId, |
| 68 | project: data.project, |
| 69 | createdAt: new Date().toISOString(), |
| 70 | }; |
| 71 | |
| 72 | await kv.set(KV.crystals, crystal.id, crystal); |
| 73 | |
| 74 | await Promise.all( |
| 75 | digest.lessons.map((lesson) => |
no test coverage detected