@almadar/agent 1.0.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.
@@ -0,0 +1,350 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/api-types.ts
4
+ var ExtractedRequirementsSchema = z.object({
5
+ /** Entity names to create */
6
+ entities: z.array(z.string()).optional().default([]),
7
+ /** State names that should exist */
8
+ states: z.array(z.string()).optional().default([]),
9
+ /** Event/action names */
10
+ events: z.array(z.string()).optional().default([]),
11
+ /** Business rules (become guards) */
12
+ guards: z.array(z.string()).optional().default([]),
13
+ /** Page types needed */
14
+ pages: z.array(z.string()).optional().default([]),
15
+ /** Notifications/side-effects */
16
+ effects: z.array(z.string()).optional().default([]),
17
+ /** Raw requirement statements */
18
+ rawRequirements: z.array(z.string()).optional().default([])
19
+ });
20
+ z.object({
21
+ /** Required: The skill(s) to use for this generation */
22
+ skill: z.union([
23
+ z.string().min(1, "Skill is required"),
24
+ z.array(z.string().min(1)).min(1, "At least one skill is required")
25
+ ]),
26
+ /** The user's task/message */
27
+ message: z.string().min(1, "Message is required"),
28
+ /** Optional: Thread ID for session continuity */
29
+ threadId: z.string().uuid().optional(),
30
+ /** Optional: Workspace directory (defaults to temp dir) */
31
+ workspace: z.string().optional(),
32
+ /** Optional: LLM provider */
33
+ provider: z.enum(["anthropic", "openai", "deepseek"]).optional(),
34
+ /** Optional: Model name */
35
+ model: z.string().optional(),
36
+ /** Optional: Disable human-in-the-loop interrupts (for eval/testing) */
37
+ noInterrupt: z.boolean().optional(),
38
+ /** Optional: App ID for persisting schema to Firestore */
39
+ appId: z.string().optional(),
40
+ /** Optional: Extracted requirements from analysis phase (for orbital skill) */
41
+ requirements: ExtractedRequirementsSchema.optional(),
42
+ /** Optional: GitHub integration configuration */
43
+ github: z.object({
44
+ /** GitHub personal access token */
45
+ token: z.string().min(1, "GitHub token is required"),
46
+ /** Repository owner (e.g., 'octocat') */
47
+ owner: z.string().optional(),
48
+ /** Repository name (e.g., 'hello-world') */
49
+ repo: z.string().optional()
50
+ }).optional()
51
+ }).strict();
52
+ z.object({
53
+ /** Required: Thread ID to resume */
54
+ threadId: z.string().uuid(),
55
+ /** Required: Decisions for pending interrupts */
56
+ decisions: z.array(
57
+ z.object({
58
+ type: z.enum(["approve", "edit", "reject"]),
59
+ args: z.record(z.unknown()).optional()
60
+ })
61
+ ),
62
+ /** Optional: Approve all future actions */
63
+ approveAll: z.boolean().optional()
64
+ });
65
+ z.object({
66
+ /** Required: Thread ID to continue */
67
+ threadId: z.string().uuid(),
68
+ /** Required: Follow-up message */
69
+ message: z.string().min(1, "Message is required")
70
+ });
71
+ function createSSEEvent(type, data) {
72
+ return {
73
+ type,
74
+ data,
75
+ timestamp: Date.now()
76
+ };
77
+ }
78
+
79
+ // src/event-transformer/event-transformer.ts
80
+ var FILE_OPERATION_TOOLS = /* @__PURE__ */ new Set([
81
+ "ls",
82
+ "read_file",
83
+ "write_file",
84
+ "edit_file"
85
+ ]);
86
+ function isFileOperationTool(toolName) {
87
+ return FILE_OPERATION_TOOLS.has(toolName);
88
+ }
89
+ function extractMessageContent(msg) {
90
+ let content = null;
91
+ if (msg.kwargs && typeof msg.kwargs === "object") {
92
+ const kwargs = msg.kwargs;
93
+ content = kwargs.content;
94
+ } else if (msg.content !== void 0) {
95
+ content = msg.content;
96
+ }
97
+ if (!content) return null;
98
+ if (typeof content === "string") {
99
+ return content;
100
+ }
101
+ if (Array.isArray(content)) {
102
+ const texts = content.filter(
103
+ (block) => typeof block === "object" && block !== null && block.type === "text" && typeof block.text === "string"
104
+ ).map((block) => block.text);
105
+ if (texts.length > 0) {
106
+ return texts.join("\n");
107
+ }
108
+ }
109
+ return null;
110
+ }
111
+ function extractToolCalls(msg) {
112
+ let content = null;
113
+ let additionalKwargs = null;
114
+ if (msg.kwargs && typeof msg.kwargs === "object") {
115
+ const kwargs = msg.kwargs;
116
+ content = kwargs.content;
117
+ additionalKwargs = kwargs.additional_kwargs;
118
+ } else if (msg.content !== void 0) {
119
+ content = msg.content;
120
+ additionalKwargs = msg.additional_kwargs;
121
+ }
122
+ if (additionalKwargs?.tool_calls && Array.isArray(additionalKwargs.tool_calls)) {
123
+ const toolCalls = additionalKwargs.tool_calls.filter((tc) => tc.function?.name).map((tc) => {
124
+ let args = {};
125
+ const rawArgs = tc.function?.arguments;
126
+ const toolName = tc.function?.name || "unknown";
127
+ if (rawArgs) {
128
+ try {
129
+ args = JSON.parse(rawArgs);
130
+ } catch {
131
+ }
132
+ }
133
+ return { name: toolName, args };
134
+ });
135
+ if (toolCalls.length > 0) {
136
+ return toolCalls;
137
+ }
138
+ }
139
+ if (content && Array.isArray(content)) {
140
+ const toolCalls = content.filter(
141
+ (block) => typeof block === "object" && block !== null && block.type === "tool_use" && typeof block.name === "string"
142
+ ).map((block) => ({ name: block.name, args: block.input || {} }));
143
+ if (toolCalls.length > 0) {
144
+ return toolCalls;
145
+ }
146
+ }
147
+ return null;
148
+ }
149
+ function isAIMessage(msg) {
150
+ if (Array.isArray(msg.id) && msg.id.includes("AIMessage")) return true;
151
+ if (msg.type === "ai") return true;
152
+ return false;
153
+ }
154
+ function transformAgentEvent(event, threadId) {
155
+ const events = transformAgentEventMulti(event, threadId);
156
+ return events[0] || createSSEEvent("message", { content: "", role: "assistant", isComplete: true });
157
+ }
158
+ function transformAgentEventMulti(event, threadId) {
159
+ const events = [];
160
+ if (hasInterrupt(event)) {
161
+ events.push(createSSEEvent("interrupt", extractInterruptData(event, threadId || "unknown")));
162
+ return events;
163
+ }
164
+ if (event.tools && typeof event.tools === "object") {
165
+ const toolsData = event.tools;
166
+ if (toolsData.todos && Array.isArray(toolsData.todos) && toolsData.todos.length > 0) {
167
+ const todos = toolsData.todos.map((t, idx) => ({
168
+ id: t.id || `todo-${idx}`,
169
+ task: t.task || t.content || "",
170
+ status: t.status || "pending"
171
+ }));
172
+ events.push(createSSEEvent("todo_update", { todos }));
173
+ return events;
174
+ }
175
+ if (toolsData.messages && Array.isArray(toolsData.messages)) {
176
+ const lastMsg = toolsData.messages[toolsData.messages.length - 1];
177
+ if (lastMsg?.kwargs) {
178
+ const kwargs = lastMsg.kwargs;
179
+ const content = kwargs.content || "";
180
+ const toolName = kwargs.name || "unknown";
181
+ const success = kwargs.status !== "error";
182
+ events.push(createSSEEvent("tool_result", {
183
+ tool: toolName,
184
+ result: content,
185
+ success
186
+ }));
187
+ return events;
188
+ }
189
+ }
190
+ }
191
+ if (event.model_request && typeof event.model_request === "object") {
192
+ const modelData = event.model_request;
193
+ if (modelData.messages && Array.isArray(modelData.messages)) {
194
+ const aiMessages = modelData.messages.filter(isAIMessage);
195
+ if (aiMessages.length > 0) {
196
+ const lastAI = aiMessages[aiMessages.length - 1];
197
+ const toolCalls = extractToolCalls(lastAI);
198
+ if (toolCalls && toolCalls.length > 0) {
199
+ const toolCall2 = toolCalls[0];
200
+ if (isFileOperationTool(toolCall2.name)) {
201
+ events.push(createSSEEvent("file_operation", {
202
+ operation: toolCall2.name,
203
+ path: toolCall2.args.path || "",
204
+ success: true
205
+ }));
206
+ } else {
207
+ events.push(createSSEEvent("tool_call", {
208
+ tool: toolCall2.name,
209
+ args: toolCall2.args
210
+ }));
211
+ }
212
+ return events;
213
+ }
214
+ const content = extractMessageContent(lastAI);
215
+ if (content && content.trim()) {
216
+ events.push(createSSEEvent("message", {
217
+ content,
218
+ role: "assistant",
219
+ isComplete: false
220
+ }));
221
+ return events;
222
+ }
223
+ }
224
+ }
225
+ }
226
+ if (event.todos && Array.isArray(event.todos) && event.todos.length > 0) {
227
+ events.push(createSSEEvent("todo_update", {
228
+ todos: event.todos.map((t, idx) => ({
229
+ id: t.id || `todo-${idx}`,
230
+ task: t.task || "",
231
+ status: t.status || "pending"
232
+ }))
233
+ }));
234
+ return events;
235
+ }
236
+ const toolCall = event.tool_call || event.toolCall;
237
+ if (toolCall) {
238
+ const toolName = toolCall.name || "unknown";
239
+ const toolArgs = toolCall.args || {};
240
+ if (isFileOperationTool(toolName)) {
241
+ events.push(createSSEEvent("file_operation", {
242
+ operation: toolName,
243
+ path: toolArgs.path || "",
244
+ success: true
245
+ }));
246
+ } else {
247
+ events.push(createSSEEvent("tool_call", {
248
+ tool: toolName,
249
+ args: toolArgs
250
+ }));
251
+ }
252
+ return events;
253
+ }
254
+ const toolResult = event.tool_result || event.toolResult;
255
+ if (toolResult) {
256
+ events.push(createSSEEvent("tool_result", {
257
+ tool: toolResult.name || "unknown",
258
+ result: toolResult.result,
259
+ success: true
260
+ }));
261
+ return events;
262
+ }
263
+ if (event.messages && Array.isArray(event.messages)) {
264
+ const lastMessage = event.messages[event.messages.length - 1];
265
+ if (lastMessage && typeof lastMessage === "object") {
266
+ events.push(createSSEEvent("message", {
267
+ content: lastMessage.content || "",
268
+ role: lastMessage.role || "assistant",
269
+ isComplete: true
270
+ }));
271
+ return events;
272
+ }
273
+ }
274
+ return events;
275
+ }
276
+ function hasInterrupt(event) {
277
+ return "__interrupt__" in event && event.__interrupt__ !== void 0;
278
+ }
279
+ function extractInterruptData(event, threadId) {
280
+ const interrupts = event.__interrupt__;
281
+ const actionRequests = [];
282
+ for (const ir of interrupts || []) {
283
+ if (ir.value?.actionRequests && ir.value?.reviewConfigs) {
284
+ const { actionRequests: actions, reviewConfigs } = ir.value;
285
+ for (let i = 0; i < actions.length; i++) {
286
+ const action = actions[i];
287
+ const config = reviewConfigs[i];
288
+ actionRequests.push({
289
+ tool: action.name || "unknown",
290
+ args: action.args || {},
291
+ description: action.description,
292
+ allowedDecisions: config?.allowedDecisions || ["approve", "edit", "reject"]
293
+ });
294
+ }
295
+ } else if (ir.action) {
296
+ actionRequests.push({
297
+ tool: ir.action.tool || "unknown",
298
+ args: ir.action.toolInput || {},
299
+ allowedDecisions: ir.config?.allowedDecisions || ["approve", "edit", "reject"]
300
+ });
301
+ }
302
+ }
303
+ return { threadId, actionRequests };
304
+ }
305
+ function isTodoUpdate(event) {
306
+ if (event.tools?.todos && Array.isArray(event.tools.todos) && event.tools.todos.length > 0) {
307
+ return true;
308
+ }
309
+ return "todos" in event && Array.isArray(event.todos) && event.todos.length > 0;
310
+ }
311
+ function isFileOperation(event) {
312
+ const toolCall = event.tool_call || event.toolCall;
313
+ if (toolCall?.name && isFileOperationTool(toolCall.name)) return true;
314
+ if (event.model_request?.messages) {
315
+ const aiMessages = event.model_request.messages.filter(isAIMessage);
316
+ if (aiMessages.length > 0) {
317
+ const toolCalls = extractToolCalls(aiMessages[aiMessages.length - 1]);
318
+ if (toolCalls && toolCalls.length > 0) {
319
+ return isFileOperationTool(toolCalls[0].name);
320
+ }
321
+ }
322
+ }
323
+ return false;
324
+ }
325
+ function extractFileOperation(event) {
326
+ const toolCall = event.tool_call || event.toolCall;
327
+ if (toolCall?.name && isFileOperationTool(toolCall.name)) {
328
+ return {
329
+ operation: toolCall.name,
330
+ path: toolCall.args?.path || ""
331
+ };
332
+ }
333
+ if (event.model_request?.messages) {
334
+ const aiMessages = event.model_request.messages.filter(isAIMessage);
335
+ if (aiMessages.length > 0) {
336
+ const toolCalls = extractToolCalls(aiMessages[aiMessages.length - 1]);
337
+ if (toolCalls && toolCalls.length > 0 && isFileOperationTool(toolCalls[0].name)) {
338
+ return {
339
+ operation: toolCalls[0].name,
340
+ path: toolCalls[0].args.path || ""
341
+ };
342
+ }
343
+ }
344
+ }
345
+ return null;
346
+ }
347
+
348
+ export { extractFileOperation, extractInterruptData, hasInterrupt, isFileOperation, isTodoUpdate, transformAgentEvent, transformAgentEventMulti };
349
+ //# sourceMappingURL=index.js.map
350
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api-types.ts","../../src/event-transformer/event-transformer.ts"],"names":["toolCall"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * DeepAgent API Types\n *\n * Request/response types for the skills-only DeepAgent API.\n * All agent behavior is defined through skills - no custom prompts allowed.\n *\n * @packageDocumentation\n */\n\nimport { z } from 'zod';\n\n// ============================================================================\n// Request Schemas\n// ============================================================================\n\n/**\n * Extracted requirements schema - from analysis phase.\n * Used to provide more precise generation guidance.\n */\nexport const ExtractedRequirementsSchema = z.object({\n /** Entity names to create */\n entities: z.array(z.string()).optional().default([]),\n /** State names that should exist */\n states: z.array(z.string()).optional().default([]),\n /** Event/action names */\n events: z.array(z.string()).optional().default([]),\n /** Business rules (become guards) */\n guards: z.array(z.string()).optional().default([]),\n /** Page types needed */\n pages: z.array(z.string()).optional().default([]),\n /** Notifications/side-effects */\n effects: z.array(z.string()).optional().default([]),\n /** Raw requirement statements */\n rawRequirements: z.array(z.string()).optional().default([]),\n});\n\nexport type ExtractedRequirementsInput = z.infer<typeof ExtractedRequirementsSchema>;\n\n/**\n * Generate request schema - skills only, no custom prompts.\n */\nexport const GenerateRequestSchema = z\n .object({\n /** Required: The skill(s) to use for this generation */\n skill: z.union([\n z.string().min(1, 'Skill is required'),\n z.array(z.string().min(1)).min(1, 'At least one skill is required'),\n ]),\n\n /** The user's task/message */\n message: z.string().min(1, 'Message is required'),\n\n /** Optional: Thread ID for session continuity */\n threadId: z.string().uuid().optional(),\n\n /** Optional: Workspace directory (defaults to temp dir) */\n workspace: z.string().optional(),\n\n /** Optional: LLM provider */\n provider: z.enum(['anthropic', 'openai', 'deepseek']).optional(),\n\n /** Optional: Model name */\n model: z.string().optional(),\n\n /** Optional: Disable human-in-the-loop interrupts (for eval/testing) */\n noInterrupt: z.boolean().optional(),\n\n /** Optional: App ID for persisting schema to Firestore */\n appId: z.string().optional(),\n\n /** Optional: Extracted requirements from analysis phase (for orbital skill) */\n requirements: ExtractedRequirementsSchema.optional(),\n\n /** Optional: GitHub integration configuration */\n github: z.object({\n /** GitHub personal access token */\n token: z.string().min(1, 'GitHub token is required'),\n /** Repository owner (e.g., 'octocat') */\n owner: z.string().optional(),\n /** Repository name (e.g., 'hello-world') */\n repo: z.string().optional(),\n }).optional(),\n })\n .strict();\n\nexport type GenerateRequest = z.infer<typeof GenerateRequestSchema>;\n\n/**\n * Resume request schema - for resuming after interrupt.\n */\nexport const ResumeRequestSchema = z.object({\n /** Required: Thread ID to resume */\n threadId: z.string().uuid(),\n\n /** Required: Decisions for pending interrupts */\n decisions: z.array(\n z.object({\n type: z.enum(['approve', 'edit', 'reject']),\n args: z.record(z.unknown()).optional(),\n })\n ),\n\n /** Optional: Approve all future actions */\n approveAll: z.boolean().optional(),\n});\n\nexport type ResumeRequest = z.infer<typeof ResumeRequestSchema>;\n\n/**\n * Decision type for interrupt responses.\n */\nexport interface Decision {\n type: 'approve' | 'edit' | 'reject';\n args?: Record<string, unknown>;\n}\n\n/**\n * Continue request schema - for multi-turn conversation.\n */\nexport const ContinueRequestSchema = z.object({\n /** Required: Thread ID to continue */\n threadId: z.string().uuid(),\n\n /** Required: Follow-up message */\n message: z.string().min(1, 'Message is required'),\n});\n\nexport type ContinueRequest = z.infer<typeof ContinueRequestSchema>;\n\n// ============================================================================\n// SSE Event Types\n// ============================================================================\n\n/**\n * All possible SSE event types.\n */\nexport type SSEEventType =\n | 'start'\n | 'message'\n | 'tool_call'\n | 'tool_result'\n | 'todo_update'\n | 'todo_detail'\n | 'file_operation'\n | 'schema_update'\n | 'generation_log'\n | 'subagent_event'\n | 'interrupt'\n | 'error'\n | 'complete'\n | 'cancelled'\n | 'app_created'\n | 'schema_phase_validated'\n | 'schema_phase_update'\n | 'orbital_added'\n | 'orbital_schema_complete'\n | 'changeset_recorded'\n | 'snapshot_created';\n\n/**\n * Base SSE event structure.\n */\nexport interface SSEEventBase {\n type: SSEEventType;\n timestamp: number;\n}\n\n/**\n * Start event - sent when streaming begins.\n */\nexport interface StartEvent extends SSEEventBase {\n type: 'start';\n data: {\n threadId: string;\n skill: string;\n workDir: string;\n };\n}\n\n/**\n * Message event - agent text output.\n */\nexport interface MessageEvent extends SSEEventBase {\n type: 'message';\n data: {\n content: string;\n role: 'assistant' | 'user' | 'system';\n isComplete: boolean;\n };\n}\n\n/**\n * Tool call event - when agent invokes a tool.\n */\nexport interface ToolCallEvent extends SSEEventBase {\n type: 'tool_call';\n data: {\n tool: string;\n args: Record<string, unknown>;\n };\n}\n\n/**\n * Tool result event - tool execution result.\n */\nexport interface ToolResultEvent extends SSEEventBase {\n type: 'tool_result';\n data: {\n tool: string;\n result: unknown;\n success: boolean;\n };\n}\n\n/**\n * Todo update event - task progress.\n */\nexport interface TodoUpdateEvent extends SSEEventBase {\n type: 'todo_update';\n data: {\n todos: Array<{\n id: string;\n task: string;\n status: 'pending' | 'in_progress' | 'completed';\n }>;\n };\n}\n\n/**\n * Activity type for todo details.\n */\nexport type TodoActivityType = 'thinking' | 'tool_call' | 'tool_result' | 'code_change';\n\n/**\n * Todo detail event - shows LLM activity for a specific todo.\n */\nexport interface TodoDetailEvent extends SSEEventBase {\n type: 'todo_detail';\n data: {\n todoId: string;\n activityType: TodoActivityType;\n content: string;\n tool?: string;\n args?: Record<string, unknown>;\n success?: boolean;\n filePath?: string;\n diff?: string;\n };\n}\n\n/**\n * File operation event.\n */\nexport interface FileOperationEvent extends SSEEventBase {\n type: 'file_operation';\n data: {\n operation: 'ls' | 'read_file' | 'write_file' | 'edit_file';\n path: string;\n success: boolean;\n };\n}\n\n/**\n * Schema update event.\n */\nexport interface SchemaUpdateEvent extends SSEEventBase {\n type: 'schema_update';\n data: {\n appId: string;\n version: number;\n schema: Record<string, unknown>;\n isNew: boolean;\n snapshotId?: string;\n changesetId?: string;\n };\n}\n\n/**\n * Generation log event.\n */\nexport interface GenerationLogEvent extends SSEEventBase {\n type: 'generation_log';\n data: {\n level: 'info' | 'warn' | 'error' | 'debug';\n message: string;\n data?: Record<string, unknown>;\n orbitalName?: string;\n };\n}\n\n/**\n * Interrupt event - awaiting human decision.\n */\nexport interface InterruptEvent extends SSEEventBase {\n type: 'interrupt';\n data: {\n threadId: string;\n actionRequests: Array<{\n tool: string;\n args: Record<string, unknown>;\n allowedDecisions: ('approve' | 'edit' | 'reject')[];\n description?: string;\n }>;\n };\n}\n\n/**\n * Error event.\n */\nexport interface ErrorEvent extends SSEEventBase {\n type: 'error';\n data: {\n error: string;\n code?: string;\n };\n}\n\n/**\n * Cancelled event.\n */\nexport interface CancelledEvent extends SSEEventBase {\n type: 'cancelled';\n data: {\n threadId: string;\n message: string;\n };\n}\n\n/**\n * Complete event - when generation finishes.\n */\nexport interface CompleteEvent extends SSEEventBase {\n type: 'complete';\n data: {\n threadId: string;\n skill: string;\n workDir: string;\n schemaGenerated: boolean;\n appCompiled: boolean;\n schema?: Record<string, unknown>;\n appId?: string;\n schemaPersisted?: boolean;\n snapshotId?: string;\n changesetId?: string;\n };\n}\n\n/**\n * Subagent event - forwards events from nested agent.\n */\nexport interface SubagentEvent extends SSEEventBase {\n type: 'subagent_event';\n data: {\n orbitalName: string;\n orbitalIndex: number;\n totalOrbitals: number;\n event: {\n type: Exclude<SSEEventType, 'subagent_event'>;\n data: Record<string, unknown>;\n timestamp: number;\n };\n };\n}\n\n/**\n * App created event.\n */\nexport interface AppCreatedEvent extends SSEEventBase {\n type: 'app_created';\n data: {\n appId: string;\n name?: string;\n orbitalCount?: number;\n fromOrbitalPersistence?: boolean;\n };\n}\n\n/**\n * Schema phase validated event.\n */\nexport interface SchemaPhaseValidatedEvent extends SSEEventBase {\n type: 'schema_phase_validated';\n data: {\n appId: string;\n success: boolean;\n errors?: unknown[];\n };\n}\n\n/**\n * Schema phase update event.\n */\nexport interface SchemaPhaseUpdateEvent extends SSEEventBase {\n type: 'schema_phase_update';\n data: Record<string, unknown>;\n}\n\n/**\n * Orbital added event.\n */\nexport interface OrbitalAddedEvent extends SSEEventBase {\n type: 'orbital_added';\n data: {\n appId: string;\n orbitalName: string;\n orbitalIndex: number;\n totalOrbitals: number;\n isNew?: boolean;\n orbitalSchema?: Record<string, unknown>;\n };\n}\n\n/**\n * Orbital schema complete event.\n */\nexport interface OrbitalSchemaCompleteEvent extends SSEEventBase {\n type: 'orbital_schema_complete';\n data: {\n appId: string;\n totalOrbitals: number;\n orbitalNames: string[];\n };\n}\n\n/**\n * Changeset recorded event.\n */\nexport interface ChangesetRecordedEvent extends SSEEventBase {\n type: 'changeset_recorded';\n data: {\n appId: string;\n changesetId: string;\n version: number;\n trackingMode: 'initial' | 'update';\n summary: {\n added: number;\n modified: number;\n removed: number;\n };\n source?: string;\n };\n}\n\n/**\n * Snapshot created event.\n */\nexport interface SnapshotCreatedEvent extends SSEEventBase {\n type: 'snapshot_created';\n data: {\n appId: string;\n snapshotId: string;\n version: number;\n reason: string;\n };\n}\n\n/**\n * Union of all SSE event types.\n */\nexport type SSEEvent =\n | StartEvent\n | MessageEvent\n | ToolCallEvent\n | ToolResultEvent\n | TodoUpdateEvent\n | TodoDetailEvent\n | FileOperationEvent\n | SchemaUpdateEvent\n | GenerationLogEvent\n | SubagentEvent\n | InterruptEvent\n | ErrorEvent\n | CancelledEvent\n | CompleteEvent\n | AppCreatedEvent\n | SchemaPhaseValidatedEvent\n | SchemaPhaseUpdateEvent\n | OrbitalAddedEvent\n | OrbitalSchemaCompleteEvent\n | ChangesetRecordedEvent\n | SnapshotCreatedEvent;\n\n// ============================================================================\n// Response Types\n// ============================================================================\n\n/**\n * List skills response.\n */\nexport interface ListSkillsResponse {\n available: Array<{\n name: string;\n description: string;\n allowedTools?: string[];\n }>;\n installed: Array<{\n name: string;\n description: string;\n allowedTools?: string[];\n }>;\n}\n\n/**\n * Session info response.\n */\nexport interface SessionInfo {\n threadId: string;\n skill: string;\n workDir: string;\n createdAt: number;\n lastActivityAt: number;\n}\n\n/**\n * List sessions response.\n */\nexport interface ListSessionsResponse {\n sessions: SessionInfo[];\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create an SSE event with timestamp.\n */\nexport function createSSEEvent<T extends SSEEventType>(\n type: T,\n data: Extract<SSEEvent, { type: T }>['data']\n): Extract<SSEEvent, { type: T }> {\n return {\n type,\n data,\n timestamp: Date.now(),\n } as Extract<SSEEvent, { type: T }>;\n}\n\n/**\n * Format an SSE event for transmission.\n */\nexport function formatSSEEvent(event: SSEEvent): string {\n return `data: ${JSON.stringify(event)}\\n\\n`;\n}\n\n/**\n * Parse an SSE event from a data string.\n */\nexport function parseSSEEvent(data: string): SSEEvent {\n return JSON.parse(data) as SSEEvent;\n}\n\n/**\n * Type guard for SSE start events.\n */\nexport function isSSEStartEvent(event: SSEEvent): event is StartEvent {\n return event.type === 'start';\n}\n\n/**\n * Type guard for SSE message events.\n */\nexport function isSSEMessageEvent(event: SSEEvent): event is MessageEvent {\n return event.type === 'message';\n}\n\n/**\n * Type guard for SSE interrupt events.\n */\nexport function isSSEInterruptEvent(event: SSEEvent): event is InterruptEvent {\n return event.type === 'interrupt';\n}\n\n/**\n * Type guard for SSE complete events.\n */\nexport function isSSECompleteEvent(event: SSEEvent): event is CompleteEvent {\n return event.type === 'complete';\n}\n\n/**\n * Type guard for SSE error events.\n */\nexport function isSSEErrorEvent(event: SSEEvent): event is ErrorEvent {\n return event.type === 'error';\n}\n\n/**\n * Type guard for SSE tool call events.\n */\nexport function isSSEToolCallEvent(event: SSEEvent): event is ToolCallEvent {\n return event.type === 'tool_call';\n}\n\n/**\n * Type guard for SSE todo update events.\n */\nexport function isSSETodoUpdateEvent(event: SSEEvent): event is TodoUpdateEvent {\n return event.type === 'todo_update';\n}\n\n/**\n * Type guard for SSE todo detail events.\n */\nexport function isSSETodoDetailEvent(event: SSEEvent): event is TodoDetailEvent {\n return event.type === 'todo_detail';\n}\n\n/**\n * Type guard for SSE subagent events.\n */\nexport function isSSESubagentEvent(event: SSEEvent): event is SubagentEvent {\n return event.type === 'subagent_event';\n}\n\n/**\n * Type guard for SSE generation log events.\n */\nexport function isSSEGenerationLogEvent(event: SSEEvent): event is GenerationLogEvent {\n return event.type === 'generation_log';\n}\n","/**\n * Event Transformer for DeepAgent\n *\n * Transforms raw LangGraph/deepagents events into SSE events.\n * Handles special events like todo updates and file operations.\n *\n * Supports both:\n * - LangGraph event structures (event.tools, event.model_request)\n * - Legacy flat event structures (event.todos, event.tool_call)\n */\n\nimport {\n createSSEEvent,\n type SSEEvent,\n} from '../api-types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Raw agent event from LangGraph/deepagents.\n */\nexport interface RawAgentEvent {\n // LangGraph nested structures\n tools?: {\n todos?: Array<{ content?: string; task?: string; status?: string; id?: string }>;\n messages?: Array<Record<string, unknown>>;\n };\n model_request?: {\n messages?: Array<Record<string, unknown>>;\n };\n\n // Legacy flat structures\n messages?: Array<{\n role?: string;\n content?: string;\n }>;\n tool_call?: {\n name?: string;\n args?: Record<string, unknown>;\n };\n toolCall?: {\n name?: string;\n args?: Record<string, unknown>;\n };\n tool_result?: {\n name?: string;\n result?: unknown;\n };\n toolResult?: {\n name?: string;\n result?: unknown;\n };\n todos?: Array<{\n id?: string;\n task?: string;\n status?: 'pending' | 'in_progress' | 'completed';\n }>;\n\n // Interrupt events (both formats)\n __interrupt__?: Array<{\n value?: {\n actionRequests?: Array<{ name?: string; args?: Record<string, unknown>; description?: string }>;\n reviewConfigs?: Array<{ allowedDecisions?: string[] }>;\n };\n action?: {\n tool?: string;\n toolInput?: Record<string, unknown>;\n };\n config?: {\n allowedDecisions?: string[];\n };\n }>;\n\n // Other fields\n [key: string]: unknown;\n}\n\n// ============================================================================\n// File Operation Detection\n// ============================================================================\n\n/**\n * File operation tool names from FilesystemMiddleware.\n */\nconst FILE_OPERATION_TOOLS = new Set([\n 'ls',\n 'read_file',\n 'write_file',\n 'edit_file',\n]);\n\n/**\n * Check if a tool name is a file operation.\n */\nfunction isFileOperationTool(toolName: string): boolean {\n return FILE_OPERATION_TOOLS.has(toolName);\n}\n\n// ============================================================================\n// LangGraph Message Extraction Helpers\n// ============================================================================\n\n/**\n * Extract text content from a LangChain message object.\n * Handles both serialized format (kwargs.content) and deserialized format (content directly).\n */\nfunction extractMessageContent(msg: Record<string, unknown>): string | null {\n let content: unknown = null;\n\n if (msg.kwargs && typeof msg.kwargs === 'object') {\n const kwargs = msg.kwargs as Record<string, unknown>;\n content = kwargs.content;\n } else if (msg.content !== undefined) {\n content = msg.content;\n }\n\n if (!content) return null;\n\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter((block): block is { type: string; text: string } =>\n typeof block === 'object' && block !== null && block.type === 'text' && typeof block.text === 'string'\n )\n .map(block => block.text);\n if (texts.length > 0) {\n return texts.join('\\n');\n }\n }\n\n return null;\n}\n\n/**\n * Extract tool calls from a LangChain AI message.\n * Handles both Anthropic format (tool_use in content) and OpenAI/DeepSeek format (tool_calls in additional_kwargs).\n */\nfunction extractToolCalls(msg: Record<string, unknown>): Array<{ name: string; args: Record<string, unknown> }> | null {\n let content: unknown = null;\n let additionalKwargs: Record<string, unknown> | null = null;\n\n if (msg.kwargs && typeof msg.kwargs === 'object') {\n const kwargs = msg.kwargs as Record<string, unknown>;\n content = kwargs.content;\n additionalKwargs = kwargs.additional_kwargs as Record<string, unknown> | null;\n } else if (msg.content !== undefined) {\n content = msg.content;\n additionalKwargs = msg.additional_kwargs as Record<string, unknown> | null;\n }\n\n // Try OpenAI/DeepSeek format first: tool_calls in additional_kwargs\n if (additionalKwargs?.tool_calls && Array.isArray(additionalKwargs.tool_calls)) {\n const toolCalls = (additionalKwargs.tool_calls as Array<{\n id?: string;\n type?: string;\n function?: { name: string; arguments?: string };\n }>)\n .filter(tc => tc.function?.name)\n .map(tc => {\n let args: Record<string, unknown> = {};\n const rawArgs = tc.function?.arguments;\n const toolName = tc.function?.name || 'unknown';\n\n if (rawArgs) {\n try {\n args = JSON.parse(rawArgs);\n } catch {\n // If JSON parse fails, skip\n }\n }\n return { name: toolName, args };\n });\n\n if (toolCalls.length > 0) {\n return toolCalls;\n }\n }\n\n // Try Anthropic format: tool_use blocks in content array\n if (content && Array.isArray(content)) {\n const toolCalls = content\n .filter((block): block is { type: string; name: string; input?: Record<string, unknown> } =>\n typeof block === 'object' && block !== null && block.type === 'tool_use' && typeof block.name === 'string'\n )\n .map(block => ({ name: block.name, args: block.input || {} }));\n\n if (toolCalls.length > 0) {\n return toolCalls;\n }\n }\n\n return null;\n}\n\n/**\n * Check if a message is an AI message.\n */\nfunction isAIMessage(msg: Record<string, unknown>): boolean {\n if (Array.isArray(msg.id) && (msg.id as string[]).includes('AIMessage')) return true;\n if ((msg as { type?: string }).type === 'ai') return true;\n return false;\n}\n\n// ============================================================================\n// Event Transformation\n// ============================================================================\n\n/**\n * Transform a raw agent event to SSE event(s).\n *\n * Handles both LangGraph nested structures and legacy flat structures.\n * Returns an array for consistency with multi-event scenarios.\n *\n * @param event Raw agent event\n * @param threadId Thread ID for context\n * @returns Array of SSE events\n */\nexport function transformAgentEvent(\n event: RawAgentEvent,\n threadId?: string\n): SSEEvent {\n const events = transformAgentEventMulti(event, threadId);\n return events[0] || createSSEEvent('message', { content: '', role: 'assistant', isComplete: true });\n}\n\n/**\n * Transform a raw agent event to multiple SSE events.\n * Use this when you need to handle all events from a single LangGraph event.\n */\nexport function transformAgentEventMulti(\n event: RawAgentEvent,\n threadId?: string\n): SSEEvent[] {\n const events: SSEEvent[] = [];\n\n // 1. Handle interrupts (highest priority)\n if (hasInterrupt(event)) {\n events.push(createSSEEvent('interrupt', extractInterruptData(event, threadId || 'unknown')));\n return events;\n }\n\n // 2. Handle LangGraph tools events (contains todos OR tool results)\n if (event.tools && typeof event.tools === 'object') {\n const toolsData = event.tools;\n\n // Check for todo updates from TodoListMiddleware\n if (toolsData.todos && Array.isArray(toolsData.todos) && toolsData.todos.length > 0) {\n const todos = toolsData.todos.map((t, idx) => ({\n id: t.id || `todo-${idx}`,\n task: t.task || t.content || '',\n status: (t.status as 'pending' | 'in_progress' | 'completed') || 'pending',\n }));\n events.push(createSSEEvent('todo_update', { todos }));\n return events;\n }\n\n // Check for tool execution results (ToolMessage)\n if (toolsData.messages && Array.isArray(toolsData.messages)) {\n const lastMsg = toolsData.messages[toolsData.messages.length - 1];\n if (lastMsg?.kwargs) {\n const kwargs = lastMsg.kwargs as { content?: string; name?: string; status?: string };\n const content = kwargs.content || '';\n const toolName = kwargs.name || 'unknown';\n const success = kwargs.status !== 'error';\n\n events.push(createSSEEvent('tool_result', {\n tool: toolName,\n result: content,\n success,\n }));\n return events;\n }\n }\n }\n\n // 3. Handle LangGraph model_request (AI thinking/tool calls)\n if (event.model_request && typeof event.model_request === 'object') {\n const modelData = event.model_request as { messages?: Array<Record<string, unknown>> };\n if (modelData.messages && Array.isArray(modelData.messages)) {\n // Find the last AI message\n const aiMessages = modelData.messages.filter(isAIMessage);\n\n if (aiMessages.length > 0) {\n const lastAI = aiMessages[aiMessages.length - 1];\n\n // Check for tool calls first\n const toolCalls = extractToolCalls(lastAI);\n if (toolCalls && toolCalls.length > 0) {\n const toolCall = toolCalls[0];\n\n // Check if it's a file operation\n if (isFileOperationTool(toolCall.name)) {\n events.push(createSSEEvent('file_operation', {\n operation: toolCall.name as 'ls' | 'read_file' | 'write_file' | 'edit_file',\n path: (toolCall.args.path as string) || '',\n success: true,\n }));\n } else {\n events.push(createSSEEvent('tool_call', {\n tool: toolCall.name,\n args: toolCall.args,\n }));\n }\n return events;\n }\n\n // Extract text content (AI thinking)\n const content = extractMessageContent(lastAI);\n if (content && content.trim()) {\n events.push(createSSEEvent('message', {\n content: content,\n role: 'assistant',\n isComplete: false,\n }));\n return events;\n }\n }\n }\n }\n\n // 4. Handle legacy flat todo updates\n if (event.todos && Array.isArray(event.todos) && event.todos.length > 0) {\n events.push(createSSEEvent('todo_update', {\n todos: event.todos.map((t, idx) => ({\n id: t.id || `todo-${idx}`,\n task: t.task || '',\n status: t.status || 'pending',\n })),\n }));\n return events;\n }\n\n // 5. Handle legacy flat tool calls\n const toolCall = event.tool_call || event.toolCall;\n if (toolCall) {\n const toolName = toolCall.name || 'unknown';\n const toolArgs = toolCall.args || {};\n\n if (isFileOperationTool(toolName)) {\n events.push(createSSEEvent('file_operation', {\n operation: toolName as 'ls' | 'read_file' | 'write_file' | 'edit_file',\n path: (toolArgs.path as string) || '',\n success: true,\n }));\n } else {\n events.push(createSSEEvent('tool_call', {\n tool: toolName,\n args: toolArgs,\n }));\n }\n return events;\n }\n\n // 6. Handle legacy flat tool results\n const toolResult = event.tool_result || event.toolResult;\n if (toolResult) {\n events.push(createSSEEvent('tool_result', {\n tool: toolResult.name || 'unknown',\n result: toolResult.result,\n success: true,\n }));\n return events;\n }\n\n // 7. Handle legacy flat messages\n if (event.messages && Array.isArray(event.messages)) {\n const lastMessage = event.messages[event.messages.length - 1];\n if (lastMessage && typeof lastMessage === 'object') {\n events.push(createSSEEvent('message', {\n content: lastMessage.content || '',\n role: (lastMessage.role as 'assistant' | 'user' | 'system') || 'assistant',\n isComplete: true,\n }));\n return events;\n }\n }\n\n // 8. Default: skip unknown events\n return events;\n}\n\n/**\n * Check if an event contains an interrupt.\n */\nexport function hasInterrupt(event: RawAgentEvent): boolean {\n return '__interrupt__' in event && event.__interrupt__ !== undefined;\n}\n\n/**\n * Extract interrupt data from an event.\n */\nexport function extractInterruptData(event: RawAgentEvent, threadId: string): {\n threadId: string;\n actionRequests: Array<{\n tool: string;\n args: Record<string, unknown>;\n allowedDecisions: ('approve' | 'edit' | 'reject')[];\n description?: string;\n }>;\n} {\n const interrupts = event.__interrupt__;\n const actionRequests: Array<{\n tool: string;\n args: Record<string, unknown>;\n allowedDecisions: ('approve' | 'edit' | 'reject')[];\n description?: string;\n }> = [];\n\n for (const ir of interrupts || []) {\n // New HITL middleware format (value.actionRequests + value.reviewConfigs)\n if (ir.value?.actionRequests && ir.value?.reviewConfigs) {\n const { actionRequests: actions, reviewConfigs } = ir.value;\n for (let i = 0; i < actions.length; i++) {\n const action = actions[i];\n const config = reviewConfigs[i];\n actionRequests.push({\n tool: action.name || 'unknown',\n args: action.args || {},\n description: action.description,\n allowedDecisions: (config?.allowedDecisions as ('approve' | 'edit' | 'reject')[]) || ['approve', 'edit', 'reject'],\n });\n }\n }\n // Legacy format support\n else if (ir.action) {\n actionRequests.push({\n tool: ir.action.tool || 'unknown',\n args: ir.action.toolInput || {},\n allowedDecisions: (ir.config?.allowedDecisions as ('approve' | 'edit' | 'reject')[]) || ['approve', 'edit', 'reject'],\n });\n }\n }\n\n return { threadId, actionRequests };\n}\n\n/**\n * Check if an event is a todo update.\n */\nexport function isTodoUpdate(event: RawAgentEvent): boolean {\n // Check both LangGraph and legacy formats\n if (event.tools?.todos && Array.isArray(event.tools.todos) && event.tools.todos.length > 0) {\n return true;\n }\n return 'todos' in event && Array.isArray(event.todos) && event.todos.length > 0;\n}\n\n/**\n * Check if an event is a file operation.\n */\nexport function isFileOperation(event: RawAgentEvent): boolean {\n const toolCall = event.tool_call || event.toolCall;\n if (toolCall?.name && isFileOperationTool(toolCall.name)) return true;\n\n // Check LangGraph format\n if (event.model_request?.messages) {\n const aiMessages = event.model_request.messages.filter(isAIMessage);\n if (aiMessages.length > 0) {\n const toolCalls = extractToolCalls(aiMessages[aiMessages.length - 1] as Record<string, unknown>);\n if (toolCalls && toolCalls.length > 0) {\n return isFileOperationTool(toolCalls[0].name);\n }\n }\n }\n\n return false;\n}\n\n/**\n * Extract file operation details from an event.\n */\nexport function extractFileOperation(event: RawAgentEvent): {\n operation: string;\n path: string;\n} | null {\n const toolCall = event.tool_call || event.toolCall;\n if (toolCall?.name && isFileOperationTool(toolCall.name)) {\n return {\n operation: toolCall.name,\n path: (toolCall.args?.path as string) || '',\n };\n }\n\n // Check LangGraph format\n if (event.model_request?.messages) {\n const aiMessages = event.model_request.messages.filter(isAIMessage);\n if (aiMessages.length > 0) {\n const toolCalls = extractToolCalls(aiMessages[aiMessages.length - 1] as Record<string, unknown>);\n if (toolCalls && toolCalls.length > 0 && isFileOperationTool(toolCalls[0].name)) {\n return {\n operation: toolCalls[0].name,\n path: (toolCalls[0].args.path as string) || '',\n };\n }\n }\n }\n\n return null;\n}\n"]}
@@ -0,0 +1,184 @@
1
+ import { BaseCheckpointSaver, CheckpointTuple, CheckpointListOptions, Checkpoint, CheckpointMetadata, PendingWrite } from '@langchain/langgraph-checkpoint';
2
+ import { RunnableConfig } from '@langchain/core/runnables';
3
+
4
+ /**
5
+ * Persistence Types
6
+ *
7
+ * Interfaces for pluggable persistence backends.
8
+ * Consumers provide implementations (memory, Firestore, etc.)
9
+ */
10
+ /**
11
+ * Session metadata stored by any backend.
12
+ */
13
+ interface SessionMetadata {
14
+ skill: string;
15
+ workDir: string;
16
+ createdAt: number;
17
+ lastActivityAt: number;
18
+ /** If true, auto-approve all future interrupts without user interaction */
19
+ approveAll?: boolean;
20
+ }
21
+ /**
22
+ * Session record with thread ID (for listing).
23
+ */
24
+ interface SessionRecord extends SessionMetadata {
25
+ threadId: string;
26
+ }
27
+ /**
28
+ * Persistence mode for agent sessions.
29
+ * - 'memory': In-memory storage (default, lost on restart)
30
+ * - 'firestore': Firestore-backed storage (persistent)
31
+ */
32
+ type PersistenceMode = 'memory' | 'firestore';
33
+ /**
34
+ * Session data for Firestore storage.
35
+ */
36
+ interface Session {
37
+ threadId: string;
38
+ skill: string;
39
+ workDir: string;
40
+ userId?: string;
41
+ createdAt: Date;
42
+ lastActivityAt: Date;
43
+ }
44
+
45
+ /**
46
+ * Firestore Checkpointer for LangGraph
47
+ *
48
+ * Custom implementation of BaseCheckpointSaver using Firebase Firestore.
49
+ * This is required because LangGraph only provides Postgres/Redis savers.
50
+ *
51
+ * IMPORTANT: This module does NOT import firebase-admin directly.
52
+ * The Firestore `db` instance must be injected via constructor options.
53
+ * This keeps the @almadar/agent package free of firebase-admin as a direct dependency.
54
+ */
55
+
56
+ /**
57
+ * Minimal Firestore interface to avoid importing firebase-admin.
58
+ * Consumers pass their own Firestore instance.
59
+ */
60
+ interface FirestoreDb {
61
+ collection(path: string): FirestoreCollectionRef;
62
+ batch(): FirestoreBatch;
63
+ }
64
+ interface FirestoreCollectionRef {
65
+ doc(id: string): FirestoreDocRef;
66
+ where(field: string, op: string, value: unknown): FirestoreQuery;
67
+ orderBy(field: string, direction?: string): FirestoreQuery;
68
+ limit(n: number): FirestoreQuery;
69
+ }
70
+ interface FirestoreDocRef {
71
+ set(data: unknown): Promise<unknown>;
72
+ get(): Promise<FirestoreDocSnapshot>;
73
+ update(data: unknown): Promise<unknown>;
74
+ delete(): Promise<unknown>;
75
+ readonly ref: unknown;
76
+ }
77
+ interface FirestoreDocSnapshot {
78
+ exists: boolean;
79
+ data(): Record<string, unknown> | undefined;
80
+ readonly ref: unknown;
81
+ }
82
+ interface FirestoreQuery {
83
+ where(field: string, op: string, value: unknown): FirestoreQuery;
84
+ orderBy(field: string, direction?: string): FirestoreQuery;
85
+ limit(n: number): FirestoreQuery;
86
+ startAfter(doc: unknown): FirestoreQuery;
87
+ get(): Promise<FirestoreQuerySnapshot>;
88
+ }
89
+ interface FirestoreQuerySnapshot {
90
+ empty: boolean;
91
+ docs: FirestoreQueryDocSnapshot[];
92
+ size: number;
93
+ }
94
+ interface FirestoreQueryDocSnapshot {
95
+ data(): Record<string, unknown>;
96
+ readonly ref: unknown;
97
+ }
98
+ interface FirestoreBatch {
99
+ set(ref: unknown, data: unknown): void;
100
+ delete(ref: unknown): void;
101
+ commit(): Promise<unknown>;
102
+ }
103
+ /**
104
+ * Firestore Timestamp-like interface.
105
+ */
106
+ interface FirestoreTimestamp {
107
+ toDate(): Date;
108
+ }
109
+ /**
110
+ * Options for FirestoreCheckpointer.
111
+ */
112
+ interface FirestoreCheckpointerOptions {
113
+ /**
114
+ * Firestore instance. Required — injected by consumer.
115
+ */
116
+ db: FirestoreDb;
117
+ /**
118
+ * Collection name for checkpoints.
119
+ * @default 'agent_checkpoints'
120
+ */
121
+ checkpointsCollection?: string;
122
+ /**
123
+ * Collection name for pending writes.
124
+ * @default 'agent_writes'
125
+ */
126
+ writesCollection?: string;
127
+ }
128
+ /**
129
+ * Firestore-backed checkpointer for LangGraph agents.
130
+ *
131
+ * Provides persistent checkpoint storage across server restarts.
132
+ * Thread checkpoints are stored as Firestore documents.
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * import { getFirestore } from 'firebase-admin/firestore';
137
+ *
138
+ * const checkpointer = new FirestoreCheckpointer({
139
+ * db: getFirestore(),
140
+ * checkpointsCollection: 'agent_checkpoints',
141
+ * });
142
+ *
143
+ * const agent = createDeepAgent({
144
+ * // ...
145
+ * checkpointer,
146
+ * });
147
+ * ```
148
+ */
149
+ declare class FirestoreCheckpointer extends BaseCheckpointSaver {
150
+ private db;
151
+ private checkpointsCollection;
152
+ private writesCollection;
153
+ constructor(options: FirestoreCheckpointerOptions);
154
+ /**
155
+ * Get thread ID from config.
156
+ */
157
+ private getThreadId;
158
+ /**
159
+ * Get checkpoint ID from config, or undefined for latest.
160
+ */
161
+ private getCheckpointId;
162
+ /**
163
+ * Get checkpoint by config.
164
+ */
165
+ getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
166
+ /**
167
+ * List checkpoints for a thread.
168
+ */
169
+ list(config: RunnableConfig, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple>;
170
+ /**
171
+ * Save a checkpoint.
172
+ */
173
+ put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata, _newVersions: Record<string, number | string>): Promise<RunnableConfig>;
174
+ /**
175
+ * Store pending writes for a checkpoint.
176
+ */
177
+ putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise<void>;
178
+ /**
179
+ * Delete all checkpoints and writes for a thread.
180
+ */
181
+ deleteThread(threadId: string): Promise<void>;
182
+ }
183
+
184
+ export { FirestoreCheckpointer as F, type PersistenceMode as P, type Session as S, type FirestoreCheckpointerOptions as a, type FirestoreDb as b, type FirestoreTimestamp as c, type SessionMetadata as d, type SessionRecord as e };