@portel/photon-core 1.3.0 → 1.4.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,238 @@
1
+ /**
2
+ * Stateful Workflow Execution with JSONL Persistence
3
+ *
4
+ * Enables photon workflows to be paused, resumed, and recovered across daemon restarts.
5
+ *
6
+ * ══════════════════════════════════════════════════════════════════════════════
7
+ * DESIGN PHILOSOPHY
8
+ * ══════════════════════════════════════════════════════════════════════════════
9
+ *
10
+ * Stateful workflows use an append-only JSONL log for persistence:
11
+ * - Each line is a self-contained JSON entry (start, emit, checkpoint, ask, answer, return, error)
12
+ * - Checkpoints mark safe resume points with accumulated state
13
+ * - Developer places checkpoint AFTER side effects to ensure idempotency
14
+ * - Resume loads log, reconstructs state from last checkpoint, continues
15
+ *
16
+ * ══════════════════════════════════════════════════════════════════════════════
17
+ * CHECKPOINT PATTERN (Idempotent Resume)
18
+ * ══════════════════════════════════════════════════════════════════════════════
19
+ *
20
+ * ```typescript
21
+ * async *workflow() {
22
+ * // Step 1: Side effect (e.g., posting to Slack)
23
+ * const posted = await this.slack.post_message({ channel: '#eng', text: 'Hello' });
24
+ * yield { checkpoint: true, state: { step: 1, messageTs: posted.ts } };
25
+ *
26
+ * // Step 2: Another side effect (e.g., creating GitHub issue)
27
+ * const issue = await this.github.create_issue({ ... });
28
+ * yield { checkpoint: true, state: { step: 2, messageTs: posted.ts, issueNumber: issue.number } };
29
+ *
30
+ * return { posted, issue };
31
+ * }
32
+ * ```
33
+ *
34
+ * On resume: Load state from last checkpoint, skip to that step, continue execution.
35
+ *
36
+ * ══════════════════════════════════════════════════════════════════════════════
37
+ * JSONL LOG FORMAT
38
+ * ══════════════════════════════════════════════════════════════════════════════
39
+ *
40
+ * ~/.photon/runs/{runId}.jsonl
41
+ *
42
+ * ```jsonl
43
+ * {"t":"start","tool":"generate","params":{"week":"52"},"ts":1704067200}
44
+ * {"t":"emit","emit":"status","message":"Collecting data...","ts":1704067201}
45
+ * {"t":"checkpoint","id":"cp_1","state":{"commits":["a1b2c3"],"step":1},"ts":1704067205}
46
+ * {"t":"ask","id":"approve","ask":"confirm","message":"Continue?","ts":1704067211}
47
+ * {"t":"answer","id":"approve","value":true,"ts":1704067215}
48
+ * {"t":"return","value":{"status":"done"},"ts":1704067220}
49
+ * ```
50
+ *
51
+ * @module stateful
52
+ */
53
+ import type { StateLogEntry, WorkflowRun, WorkflowStatus } from './types.js';
54
+ import { type PhotonYield, type InputProvider, type OutputHandler } from './generator.js';
55
+ /**
56
+ * Default runs directory (~/.photon/runs)
57
+ */
58
+ export declare const RUNS_DIR: string;
59
+ /**
60
+ * Checkpoint yield - marks a safe resume point
61
+ *
62
+ * @example
63
+ * // After a side effect, checkpoint to preserve state
64
+ * const posted = await this.slack.post_message({ ... });
65
+ * yield { checkpoint: true, state: { step: 1, messageTs: posted.ts } };
66
+ */
67
+ export interface CheckpointYield {
68
+ /** Marker for checkpoint yield */
69
+ checkpoint: true;
70
+ /** State snapshot to preserve */
71
+ state: Record<string, any>;
72
+ /** Optional checkpoint ID (auto-generated if not provided) */
73
+ id?: string;
74
+ }
75
+ /**
76
+ * Extended yield type including checkpoint
77
+ */
78
+ export type StatefulYield = PhotonYield | CheckpointYield;
79
+ /**
80
+ * Type guard for checkpoint yields
81
+ */
82
+ export declare function isCheckpointYield(y: StatefulYield): y is CheckpointYield;
83
+ /**
84
+ * State log writer for a single workflow run
85
+ */
86
+ export declare class StateLog {
87
+ private runId;
88
+ private logPath;
89
+ constructor(runId: string, runsDir?: string);
90
+ /**
91
+ * Ensure runs directory exists
92
+ */
93
+ init(): Promise<void>;
94
+ /**
95
+ * Append an entry to the log
96
+ */
97
+ append(entry: Omit<StateLogEntry, 'ts'>): Promise<void>;
98
+ /**
99
+ * Write start entry
100
+ */
101
+ writeStart(tool: string, params: Record<string, any>): Promise<void>;
102
+ /**
103
+ * Write emit entry
104
+ */
105
+ writeEmit(emit: string, message?: string, data?: any): Promise<void>;
106
+ /**
107
+ * Write checkpoint entry
108
+ */
109
+ writeCheckpoint(id: string, state: Record<string, any>): Promise<void>;
110
+ /**
111
+ * Write ask entry
112
+ */
113
+ writeAsk(id: string, ask: string, message: string): Promise<void>;
114
+ /**
115
+ * Write answer entry
116
+ */
117
+ writeAnswer(id: string, value: any): Promise<void>;
118
+ /**
119
+ * Write return entry
120
+ */
121
+ writeReturn(value: any): Promise<void>;
122
+ /**
123
+ * Write error entry
124
+ */
125
+ writeError(message: string, stack?: string): Promise<void>;
126
+ /**
127
+ * Read all entries from the log
128
+ */
129
+ readAll(): Promise<StateLogEntry[]>;
130
+ /**
131
+ * Stream entries from the log (memory efficient for large logs)
132
+ */
133
+ stream(): AsyncGenerator<StateLogEntry>;
134
+ /**
135
+ * Get the log file path
136
+ */
137
+ getPath(): string;
138
+ }
139
+ /**
140
+ * Reconstructed state from a workflow log
141
+ */
142
+ export interface ResumeState {
143
+ /** Tool/method being executed */
144
+ tool: string;
145
+ /** Input parameters */
146
+ params: Record<string, any>;
147
+ /** Is workflow complete? */
148
+ isComplete: boolean;
149
+ /** Final result (if complete) */
150
+ result?: any;
151
+ /** Error (if failed) */
152
+ error?: string;
153
+ /** Last checkpoint state */
154
+ lastCheckpoint?: {
155
+ id: string;
156
+ state: Record<string, any>;
157
+ ts: number;
158
+ };
159
+ /** Answered asks (id -> value) */
160
+ answers: Record<string, any>;
161
+ /** All entries in order */
162
+ entries: StateLogEntry[];
163
+ }
164
+ /**
165
+ * Parse a workflow log and reconstruct resume state
166
+ */
167
+ export declare function parseResumeState(runId: string, runsDir?: string): Promise<ResumeState | null>;
168
+ /**
169
+ * Configuration for stateful generator execution
170
+ */
171
+ export interface StatefulExecutorConfig {
172
+ /** Run ID (generated if not provided) */
173
+ runId?: string;
174
+ /** Runs directory (defaults to ~/.photon/runs) */
175
+ runsDir?: string;
176
+ /** Photon name (for metadata) */
177
+ photon: string;
178
+ /** Tool name being executed */
179
+ tool: string;
180
+ /** Input parameters */
181
+ params: Record<string, any>;
182
+ /** Input provider for ask yields */
183
+ inputProvider: InputProvider;
184
+ /** Output handler for emit yields */
185
+ outputHandler?: OutputHandler;
186
+ /** Resume from existing run (skips to last checkpoint) */
187
+ resume?: boolean;
188
+ }
189
+ /**
190
+ * Result of stateful execution
191
+ */
192
+ export interface StatefulExecutionResult<T> {
193
+ /** Run ID */
194
+ runId: string;
195
+ /** Final result (if completed) */
196
+ result?: T;
197
+ /** Error message (if failed) */
198
+ error?: string;
199
+ /** Was this resumed from a previous run? */
200
+ resumed: boolean;
201
+ /** Final status */
202
+ status: WorkflowStatus;
203
+ }
204
+ /**
205
+ * Generate a unique run ID
206
+ */
207
+ export declare function generateRunId(): string;
208
+ /**
209
+ * Execute a stateful generator with checkpoint support
210
+ *
211
+ * @example
212
+ * const result = await executeStatefulGenerator(workflow(), {
213
+ * photon: 'weekly-report',
214
+ * tool: 'generate',
215
+ * params: { week: 52 },
216
+ * inputProvider: cliInputProvider,
217
+ * outputHandler: (emit) => console.log(emit.message)
218
+ * });
219
+ */
220
+ export declare function executeStatefulGenerator<T>(generatorFn: () => AsyncGenerator<StatefulYield, T, any>, config: StatefulExecutorConfig): Promise<StatefulExecutionResult<T>>;
221
+ /**
222
+ * List all workflow runs
223
+ */
224
+ export declare function listRuns(runsDir?: string): Promise<WorkflowRun[]>;
225
+ /**
226
+ * Get info about a specific run
227
+ */
228
+ export declare function getRunInfo(runId: string, runsDir?: string): Promise<WorkflowRun | null>;
229
+ /**
230
+ * Delete a workflow run
231
+ */
232
+ export declare function deleteRun(runId: string, runsDir?: string): Promise<void>;
233
+ /**
234
+ * Clean up completed/failed runs older than specified age
235
+ */
236
+ export declare function cleanupRuns(maxAgeMs: number, runsDir?: string): Promise<number>;
237
+ export { type StateLogEntry, type StateLogStart, type StateLogEmit, type StateLogCheckpoint, type StateLogAsk, type StateLogAnswer, type StateLogReturn, type StateLogError, type WorkflowRun, type WorkflowStatus, } from './types.js';
238
+ //# sourceMappingURL=stateful.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateful.d.ts","sourceRoot":"","sources":["../src/stateful.ts"],"names":[],"mappings":"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"}