@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.
- package/dist/generator.d.ts +236 -2
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +30 -0
- package/dist/generator.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp-client.d.ts +39 -0
- package/dist/mcp-client.d.ts.map +1 -1
- package/dist/mcp-client.js +213 -0
- package/dist/mcp-client.js.map +1 -1
- package/dist/photon-config.d.ts +86 -0
- package/dist/photon-config.d.ts.map +1 -0
- package/dist/photon-config.js +156 -0
- package/dist/photon-config.js.map +1 -0
- package/dist/schema-extractor.d.ts +99 -1
- package/dist/schema-extractor.d.ts.map +1 -1
- package/dist/schema-extractor.js +311 -5
- package/dist/schema-extractor.js.map +1 -1
- package/dist/stateful.d.ts +238 -0
- package/dist/stateful.d.ts.map +1 -0
- package/dist/stateful.js +469 -0
- package/dist/stateful.js.map +1 -0
- package/dist/types.d.ts +260 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -2
- package/src/generator.ts +270 -2
- package/src/index.ts +73 -1
- package/src/mcp-client.ts +254 -0
- package/src/photon-config.ts +201 -0
- package/src/schema-extractor.ts +353 -6
- package/src/stateful.ts +659 -0
- package/src/types.ts +289 -0
|
@@ -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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"}
|