@portel/photon-core 1.1.0 → 1.2.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.
@@ -1,205 +1,685 @@
1
1
  /**
2
- * Generator-based Tool Execution
2
+ * Generator-based Tool Execution with Ask/Emit Pattern
3
3
  *
4
- * Enables photon tools to use generator functions with `yield` for:
5
- * - User prompts (text, password, confirm, select)
6
- * - Progress updates
7
- * - Streaming responses
8
- * - Multi-step wizards
4
+ * Enables photon tools to use async generator functions with `yield` for:
5
+ * - Interactive user input (ask) - blocks until user responds
6
+ * - Real-time output (emit) - fire and forget, no response needed
9
7
  *
10
- * The runtime handles yields appropriately based on the protocol:
11
- * - REST: Extract yields as optional parameters
12
- * - WebSocket/MCP: Interactive prompts
13
- * - CLI: readline prompts
14
- * - Fallback: Native OS dialogs
8
+ * ══════════════════════════════════════════════════════════════════════════════
9
+ * DESIGN PHILOSOPHY
10
+ * ══════════════════════════════════════════════════════════════════════════════
11
+ *
12
+ * The `ask` vs `emit` pattern provides instant clarity:
13
+ * - `ask` = "I need something FROM the user" (blocks, returns value)
14
+ * - `emit` = "I'm sending something TO the user" (non-blocking, void)
15
+ *
16
+ * This maps naturally to all runtime contexts:
17
+ *
18
+ * | Runtime | ask (input) | emit (output) |
19
+ * |------------|--------------------------|----------------------------|
20
+ * | REST API | Returns 202 + continue | Included in response or SSE|
21
+ * | WebSocket | Server request → client | Server push to client |
22
+ * | CLI | Readline prompt | Console output |
23
+ * | MCP | Elicitation dialog | Notification/logging |
24
+ * | Chatbot | Bot question → user reply| Status message, typing... |
25
+ *
26
+ * ══════════════════════════════════════════════════════════════════════════════
27
+ * REST API CONTINUATION PATTERN
28
+ * ══════════════════════════════════════════════════════════════════════════════
29
+ *
30
+ * When a generator yields `ask`, REST APIs can implement a continuation flow:
31
+ *
32
+ * ```
33
+ * POST /api/google-tv/connect
34
+ * Body: { ip: "192.168.1.100" }
35
+ *
36
+ * Response (202 Accepted):
37
+ * {
38
+ * "status": "awaiting_input",
39
+ * "continuation_id": "ctx_abc123",
40
+ * "ask": { "type": "text", "id": "pairing_code", "message": "Enter code:" },
41
+ * "continue": "/api/google-tv/connect/ctx_abc123"
42
+ * }
43
+ *
44
+ * POST /api/google-tv/connect/ctx_abc123
45
+ * Body: { "pairing_code": "123456" }
46
+ *
47
+ * Response (200 OK):
48
+ * { "status": "complete", "result": { "success": true } }
49
+ * ```
50
+ *
51
+ * ══════════════════════════════════════════════════════════════════════════════
52
+ * USAGE EXAMPLE
53
+ * ══════════════════════════════════════════════════════════════════════════════
15
54
  *
16
- * @example
17
55
  * ```typescript
18
56
  * async *connect(params: { ip: string }) {
19
- * await this.startConnection(params.ip);
57
+ * yield { emit: 'status', message: 'Connecting to TV...' };
20
58
  *
59
+ * await this.startPairing(params.ip);
60
+ *
61
+ * yield { emit: 'progress', value: 0.3, message: 'Waiting for code...' };
62
+ *
63
+ * // Blocks until user provides input
21
64
  * const code: string = yield {
22
- * prompt: 'Enter the 6-digit code:',
23
- * type: 'text'
65
+ * ask: 'text',
66
+ * id: 'pairing_code',
67
+ * message: 'Enter the 6-digit code shown on TV:',
68
+ * pattern: '^[0-9]{6}$',
69
+ * required: true
24
70
  * };
25
71
  *
72
+ * yield { emit: 'status', message: 'Verifying code...' };
73
+ *
26
74
  * await this.sendCode(code);
27
- * return { success: true };
75
+ *
76
+ * yield { emit: 'toast', message: 'Connected!', type: 'success' };
77
+ *
78
+ * return { success: true, paired: true };
28
79
  * }
29
80
  * ```
81
+ *
82
+ * @module generator
30
83
  */
31
84
  /**
32
- * Text input prompt
85
+ * Base properties shared by all ask yields
33
86
  */
34
- export interface PromptYield {
35
- prompt: string;
36
- type?: 'text' | 'password';
37
- default?: string;
38
- /** Unique identifier for this prompt (auto-generated if not provided) */
87
+ interface AskBase {
88
+ /**
89
+ * Unique identifier for this input.
90
+ * Used for:
91
+ * - REST API parameter mapping (pre-provided inputs)
92
+ * - Continuation token correlation
93
+ * - Form field identification
94
+ *
95
+ * Auto-generated if not provided (ask_0, ask_1, etc.)
96
+ */
39
97
  id?: string;
40
- /** Validation pattern */
41
- pattern?: string;
42
- /** Whether this prompt is required */
98
+ /**
99
+ * The prompt message shown to the user.
100
+ * Should be clear and actionable.
101
+ */
102
+ message: string;
103
+ /**
104
+ * Whether this input is required.
105
+ * If false, user can skip/cancel.
106
+ * @default true
107
+ */
43
108
  required?: boolean;
44
109
  }
45
110
  /**
46
- * Confirmation dialog
111
+ * Text input - single line string
112
+ *
113
+ * @example
114
+ * const name: string = yield {
115
+ * ask: 'text',
116
+ * message: 'Enter your name:',
117
+ * default: 'Guest',
118
+ * placeholder: 'John Doe'
119
+ * };
120
+ */
121
+ export interface AskText extends AskBase {
122
+ ask: 'text';
123
+ /** Default value if user submits empty */
124
+ default?: string;
125
+ /** Placeholder hint shown in input field */
126
+ placeholder?: string;
127
+ /** Regex pattern for validation */
128
+ pattern?: string;
129
+ /** Minimum length */
130
+ minLength?: number;
131
+ /** Maximum length */
132
+ maxLength?: number;
133
+ }
134
+ /**
135
+ * Password input - hidden/masked string
136
+ *
137
+ * @example
138
+ * const apiKey: string = yield {
139
+ * ask: 'password',
140
+ * message: 'Enter your API key:'
141
+ * };
47
142
  */
48
- export interface ConfirmYield {
49
- confirm: string;
50
- /** Mark as dangerous action (UI can show warning styling) */
143
+ export interface AskPassword extends AskBase {
144
+ ask: 'password';
145
+ }
146
+ /**
147
+ * Confirmation - yes/no boolean
148
+ *
149
+ * @example
150
+ * const confirmed: boolean = yield {
151
+ * ask: 'confirm',
152
+ * message: 'Delete this file permanently?',
153
+ * dangerous: true
154
+ * };
155
+ */
156
+ export interface AskConfirm extends AskBase {
157
+ ask: 'confirm';
158
+ /**
159
+ * Mark as dangerous/destructive action.
160
+ * UI may show warning styling (red button, confirmation dialog).
161
+ */
51
162
  dangerous?: boolean;
52
- id?: string;
163
+ /** Default value if user just presses enter */
164
+ default?: boolean;
53
165
  }
54
166
  /**
55
- * Selection from options
167
+ * Selection from predefined options
168
+ *
169
+ * @example
170
+ * // Simple string options
171
+ * const env: string = yield {
172
+ * ask: 'select',
173
+ * message: 'Choose environment:',
174
+ * options: ['development', 'staging', 'production']
175
+ * };
176
+ *
177
+ * // Rich options with labels
178
+ * const region: string = yield {
179
+ * ask: 'select',
180
+ * message: 'Select region:',
181
+ * options: [
182
+ * { value: 'us-east-1', label: 'US East (N. Virginia)' },
183
+ * { value: 'eu-west-1', label: 'EU West (Ireland)' }
184
+ * ]
185
+ * };
186
+ *
187
+ * // Multi-select
188
+ * const features: string[] = yield {
189
+ * ask: 'select',
190
+ * message: 'Enable features:',
191
+ * options: ['auth', 'logging', 'metrics'],
192
+ * multi: true
193
+ * };
56
194
  */
57
- export interface SelectYield {
58
- select: string;
195
+ export interface AskSelect extends AskBase {
196
+ ask: 'select';
197
+ /** Available options */
59
198
  options: Array<string | {
60
199
  value: string;
61
200
  label: string;
201
+ description?: string;
62
202
  }>;
63
- /** Allow multiple selections */
203
+ /** Allow selecting multiple options */
64
204
  multi?: boolean;
65
- id?: string;
205
+ /** Default selected value(s) */
206
+ default?: string | string[];
207
+ }
208
+ /**
209
+ * Number input with optional constraints
210
+ *
211
+ * @example
212
+ * const quantity: number = yield {
213
+ * ask: 'number',
214
+ * message: 'Enter quantity:',
215
+ * min: 1,
216
+ * max: 100,
217
+ * step: 1
218
+ * };
219
+ */
220
+ export interface AskNumber extends AskBase {
221
+ ask: 'number';
222
+ /** Minimum value */
223
+ min?: number;
224
+ /** Maximum value */
225
+ max?: number;
226
+ /** Step increment */
227
+ step?: number;
228
+ /** Default value */
229
+ default?: number;
230
+ }
231
+ /**
232
+ * File selection (for supported runtimes)
233
+ *
234
+ * @example
235
+ * const file: FileInfo = yield {
236
+ * ask: 'file',
237
+ * message: 'Select a document:',
238
+ * accept: '.pdf,.doc,.docx',
239
+ * multiple: false
240
+ * };
241
+ */
242
+ export interface AskFile extends AskBase {
243
+ ask: 'file';
244
+ /** Accepted file types (MIME types or extensions) */
245
+ accept?: string;
246
+ /** Allow multiple file selection */
247
+ multiple?: boolean;
66
248
  }
67
249
  /**
68
- * Progress update (for long-running operations)
250
+ * Date/time selection
251
+ *
252
+ * @example
253
+ * const date: string = yield {
254
+ * ask: 'date',
255
+ * message: 'Select delivery date:',
256
+ * min: '2024-01-01',
257
+ * max: '2024-12-31'
258
+ * };
259
+ */
260
+ export interface AskDate extends AskBase {
261
+ ask: 'date';
262
+ /** Include time selection */
263
+ includeTime?: boolean;
264
+ /** Minimum date (ISO string) */
265
+ min?: string;
266
+ /** Maximum date (ISO string) */
267
+ max?: string;
268
+ /** Default value (ISO string) */
269
+ default?: string;
270
+ }
271
+ /**
272
+ * Union of all ask (input) yield types
273
+ */
274
+ export type AskYield = AskText | AskPassword | AskConfirm | AskSelect | AskNumber | AskFile | AskDate;
275
+ /**
276
+ * Status message - general purpose user notification
277
+ *
278
+ * Use for: progress updates, step completions, informational messages
279
+ *
280
+ * @example
281
+ * yield { emit: 'status', message: 'Connecting to server...' };
282
+ * yield { emit: 'status', message: 'Upload complete!', type: 'success' };
283
+ */
284
+ export interface EmitStatus {
285
+ emit: 'status';
286
+ /** Message to display */
287
+ message: string;
288
+ /** Message type for styling */
289
+ type?: 'info' | 'success' | 'warning' | 'error';
290
+ }
291
+ /**
292
+ * Progress update - for long-running operations
293
+ *
294
+ * Runtimes may display as: progress bar, percentage, spinner
295
+ *
296
+ * @example
297
+ * yield { emit: 'progress', value: 0.0, message: 'Starting...' };
298
+ * yield { emit: 'progress', value: 0.5, message: 'Halfway there...' };
299
+ * yield { emit: 'progress', value: 1.0, message: 'Complete!' };
69
300
  */
70
- export interface ProgressYield {
71
- progress: number;
72
- status?: string;
73
- /** Additional data to stream to client */
74
- data?: any;
301
+ export interface EmitProgress {
302
+ emit: 'progress';
303
+ /** Progress value from 0 to 1 (0% to 100%) */
304
+ value: number;
305
+ /** Optional status message */
306
+ message?: string;
307
+ /** Additional metadata */
308
+ meta?: Record<string, any>;
75
309
  }
76
310
  /**
77
- * Stream data to client
311
+ * Streaming data - for chunked responses
312
+ *
313
+ * Use for: streaming text, large file transfers, real-time data
314
+ *
315
+ * @example
316
+ * for await (const chunk of aiStream) {
317
+ * yield { emit: 'stream', data: chunk.text };
318
+ * }
319
+ * yield { emit: 'stream', data: '', final: true };
78
320
  */
79
- export interface StreamYield {
80
- stream: any;
321
+ export interface EmitStream {
322
+ emit: 'stream';
323
+ /** Data chunk to send */
324
+ data: any;
81
325
  /** Whether this is the final chunk */
82
326
  final?: boolean;
327
+ /** Content type hint */
328
+ contentType?: string;
83
329
  }
84
330
  /**
85
- * Log/debug message
331
+ * Log message - for debugging/development
332
+ *
333
+ * May be hidden in production or routed to logging system
334
+ *
335
+ * @example
336
+ * yield { emit: 'log', message: 'Processing item', level: 'debug', data: { id: 123 } };
86
337
  */
87
- export interface LogYield {
88
- log: string;
338
+ export interface EmitLog {
339
+ emit: 'log';
340
+ /** Log message */
341
+ message: string;
342
+ /** Log level */
89
343
  level?: 'debug' | 'info' | 'warn' | 'error';
344
+ /** Additional structured data */
345
+ data?: Record<string, any>;
90
346
  }
91
347
  /**
92
- * All possible yield types
348
+ * Toast notification - ephemeral popup message
349
+ *
350
+ * Use for: success confirmations, quick alerts, non-blocking notices
351
+ *
352
+ * @example
353
+ * yield { emit: 'toast', message: 'Settings saved!', type: 'success' };
354
+ * yield { emit: 'toast', message: 'Connection lost', type: 'error', duration: 5000 };
93
355
  */
94
- export type PhotonYield = PromptYield | ConfirmYield | SelectYield | ProgressYield | StreamYield | LogYield;
356
+ export interface EmitToast {
357
+ emit: 'toast';
358
+ /** Toast message */
359
+ message: string;
360
+ /** Toast type for styling */
361
+ type?: 'info' | 'success' | 'warning' | 'error';
362
+ /** Display duration in ms (0 = sticky) */
363
+ duration?: number;
364
+ }
95
365
  /**
96
- * Check if a yield requires user input
366
+ * Thinking indicator - for chatbot/AI contexts
367
+ *
368
+ * Shows user that processing is happening (typing dots, spinner)
369
+ *
370
+ * @example
371
+ * yield { emit: 'thinking', active: true };
372
+ * const result = await this.heavyComputation();
373
+ * yield { emit: 'thinking', active: false };
97
374
  */
98
- export declare function isInputYield(y: PhotonYield): y is PromptYield | ConfirmYield | SelectYield;
375
+ export interface EmitThinking {
376
+ emit: 'thinking';
377
+ /** Whether thinking indicator should be shown */
378
+ active: boolean;
379
+ }
99
380
  /**
100
- * Check if a yield is a progress update
381
+ * Rich artifact - embedded content preview
382
+ *
383
+ * Use for: images, code blocks, documents, embeds
384
+ *
385
+ * @example
386
+ * yield {
387
+ * emit: 'artifact',
388
+ * type: 'image',
389
+ * url: 'https://example.com/chart.png',
390
+ * title: 'Sales Chart Q4'
391
+ * };
392
+ *
393
+ * yield {
394
+ * emit: 'artifact',
395
+ * type: 'code',
396
+ * language: 'typescript',
397
+ * content: 'const x = 1;',
398
+ * title: 'Example'
399
+ * };
101
400
  */
102
- export declare function isProgressYield(y: PhotonYield): y is ProgressYield;
401
+ export interface EmitArtifact {
402
+ emit: 'artifact';
403
+ /** Artifact type */
404
+ type: 'image' | 'code' | 'document' | 'embed' | 'json';
405
+ /** Title/label */
406
+ title?: string;
407
+ /** URL for external content */
408
+ url?: string;
409
+ /** Inline content */
410
+ content?: string;
411
+ /** Language hint for code */
412
+ language?: string;
413
+ /** MIME type hint */
414
+ mimeType?: string;
415
+ }
103
416
  /**
104
- * Check if a yield is streaming data
417
+ * Union of all emit (output) yield types
105
418
  */
106
- export declare function isStreamYield(y: PhotonYield): y is StreamYield;
419
+ export type EmitYield = EmitStatus | EmitProgress | EmitStream | EmitLog | EmitToast | EmitThinking | EmitArtifact;
107
420
  /**
108
- * Check if a yield is a log message
421
+ * All possible yield types from a photon generator
109
422
  */
110
- export declare function isLogYield(y: PhotonYield): y is LogYield;
423
+ export type PhotonYield = AskYield | EmitYield;
111
424
  /**
112
- * Function that provides input for a yield
113
- * Runtimes implement this based on their protocol
425
+ * Check if yield is an ask (requires user input)
426
+ *
427
+ * @example
428
+ * if (isAskYield(yielded)) {
429
+ * const userInput = await promptUser(yielded);
430
+ * generator.next(userInput);
431
+ * }
432
+ */
433
+ export declare function isAskYield(y: PhotonYield): y is AskYield;
434
+ /**
435
+ * Check if yield is an emit (output only, no response needed)
436
+ *
437
+ * @example
438
+ * if (isEmitYield(yielded)) {
439
+ * handleOutput(yielded);
440
+ * generator.next(); // Continue without value
441
+ * }
442
+ */
443
+ export declare function isEmitYield(y: PhotonYield): y is EmitYield;
444
+ /**
445
+ * Get the type of an ask yield
446
+ */
447
+ export declare function getAskType(y: AskYield): AskYield['ask'];
448
+ /**
449
+ * Get the type of an emit yield
450
+ */
451
+ export declare function getEmitType(y: EmitYield): EmitYield['emit'];
452
+ /**
453
+ * Check if a function is an async generator function
454
+ *
455
+ * @example
456
+ * if (isAsyncGeneratorFunction(method)) {
457
+ * const gen = method.call(instance, params);
458
+ * await executeGenerator(gen, config);
459
+ * }
460
+ */
461
+ export declare function isAsyncGeneratorFunction(fn: any): fn is (...args: any[]) => AsyncGenerator;
462
+ /**
463
+ * Check if a value is an async generator instance (already invoked)
464
+ *
465
+ * @example
466
+ * const result = method.call(instance, params);
467
+ * if (isAsyncGenerator(result)) {
468
+ * await executeGenerator(result, config);
469
+ * }
470
+ */
471
+ export declare function isAsyncGenerator(obj: any): obj is AsyncGenerator;
472
+ /**
473
+ * Function that provides input for an ask yield.
474
+ *
475
+ * Runtimes implement this based on their capabilities:
476
+ * - CLI: readline prompts
477
+ * - MCP: elicitation dialogs
478
+ * - WebSocket: request/response messages
479
+ * - REST: throw NeedsInputError for continuation flow
480
+ *
481
+ * @example
482
+ * const cliInputProvider: InputProvider = async (ask) => {
483
+ * if (ask.ask === 'text') return await readline(ask.message);
484
+ * if (ask.ask === 'confirm') return await confirm(ask.message);
485
+ * // ...
486
+ * };
114
487
  */
115
- export type InputProvider = (yielded: PhotonYield) => Promise<any>;
488
+ export type InputProvider = (ask: AskYield) => Promise<any>;
116
489
  /**
117
- * Handler for non-input yields (progress, stream, log)
490
+ * Handler for emit yields (output).
491
+ *
492
+ * Runtimes implement this to handle output:
493
+ * - CLI: console.log, progress bar
494
+ * - WebSocket: push message to client
495
+ * - REST: collect for response or send via SSE
496
+ *
497
+ * @example
498
+ * const cliOutputHandler: OutputHandler = (emit) => {
499
+ * if (emit.emit === 'status') console.log(emit.message);
500
+ * if (emit.emit === 'progress') updateProgressBar(emit.value);
501
+ * };
118
502
  */
119
- export type OutputHandler = (yielded: PhotonYield) => void | Promise<void>;
503
+ export type OutputHandler = (emit: EmitYield) => void | Promise<void>;
120
504
  /**
121
505
  * Configuration for generator execution
122
506
  */
123
507
  export interface GeneratorExecutorConfig {
124
- /** Provides input for prompt/confirm/select yields */
508
+ /**
509
+ * Provides input values for ask yields.
510
+ * Required unless all asks are pre-provided.
511
+ */
125
512
  inputProvider: InputProvider;
126
- /** Handles progress/stream/log yields */
513
+ /**
514
+ * Handles emit yields (optional).
515
+ * If not provided, emits are silently ignored.
516
+ */
127
517
  outputHandler?: OutputHandler;
128
- /** Pre-provided inputs (for REST APIs) */
518
+ /**
519
+ * Pre-provided inputs keyed by ask id.
520
+ * Used by REST APIs to pass all inputs upfront.
521
+ *
522
+ * @example
523
+ * // If photon yields { ask: 'text', id: 'name', message: '...' }
524
+ * // and preProvidedInputs = { name: 'John' }
525
+ * // The generator receives 'John' without calling inputProvider
526
+ */
129
527
  preProvidedInputs?: Record<string, any>;
130
- /** Timeout for waiting for input (ms) */
528
+ /**
529
+ * Timeout for waiting on input (ms).
530
+ * @default 300000 (5 minutes)
531
+ */
131
532
  inputTimeout?: number;
132
533
  }
133
534
  /**
134
- * Execute a generator-based tool
535
+ * Execute a generator-based photon tool to completion.
536
+ *
537
+ * Handles the yield/resume loop:
538
+ * 1. Run generator until it yields
539
+ * 2. If ask yield: get input from provider (or pre-provided), resume with value
540
+ * 3. If emit yield: call output handler, resume without value
541
+ * 4. Repeat until generator returns
135
542
  *
136
543
  * @param generator - The async generator to execute
137
544
  * @param config - Configuration for handling yields
138
545
  * @returns The final return value of the generator
139
546
  *
140
547
  * @example
141
- * ```typescript
142
- * const result = await executeGenerator(tool.connect({ ip: '192.168.1.1' }), {
143
- * inputProvider: async (y) => {
144
- * if ('prompt' in y) return await readline(y.prompt);
145
- * if ('confirm' in y) return await confirm(y.confirm);
548
+ * const result = await executeGenerator(photon.connect({ ip: '192.168.1.1' }), {
549
+ * inputProvider: async (ask) => {
550
+ * if (ask.ask === 'text') return await readline(ask.message);
551
+ * if (ask.ask === 'confirm') return await confirm(ask.message);
146
552
  * },
147
- * outputHandler: (y) => {
148
- * if ('progress' in y) console.log(`Progress: ${y.progress}%`);
553
+ * outputHandler: (emit) => {
554
+ * if (emit.emit === 'progress') console.log(`${emit.value * 100}%`);
149
555
  * }
150
556
  * });
151
- * ```
152
557
  */
153
558
  export declare function executeGenerator<T>(generator: AsyncGenerator<PhotonYield, T, any>, config: GeneratorExecutorConfig): Promise<T>;
154
559
  /**
155
- * Check if a function is an async generator function
156
- */
157
- export declare function isAsyncGeneratorFunction(fn: any): fn is (...args: any[]) => AsyncGenerator;
158
- /**
159
- * Check if a value is an async generator (already invoked)
560
+ * Information about an ask yield extracted from a generator.
561
+ * Used to generate REST API schemas (optional parameters).
160
562
  */
161
- export declare function isAsyncGenerator(obj: any): obj is AsyncGenerator;
162
- /**
163
- * Information about a yield point extracted from a generator
164
- */
165
- export interface ExtractedYield {
563
+ export interface ExtractedAsk {
166
564
  id: string;
167
- type: 'prompt' | 'confirm' | 'select';
168
- prompt?: string;
565
+ type: AskYield['ask'];
566
+ message: string;
567
+ required?: boolean;
568
+ default?: any;
169
569
  options?: Array<string | {
170
570
  value: string;
171
571
  label: string;
172
572
  }>;
173
- default?: string;
174
- required?: boolean;
175
573
  pattern?: string;
176
- dangerous?: boolean;
177
- multi?: boolean;
574
+ min?: number;
575
+ max?: number;
178
576
  }
179
577
  /**
180
- * Extract yield information by running generator with mock provider
181
- * This is used for REST API schema generation
578
+ * Extract ask yield information by running generator with mock provider.
182
579
  *
183
- * Note: This only extracts yields that are reachable with default/empty inputs
184
- * Complex conditional yields may not be extracted
185
- */
186
- export declare function extractYields(generatorFn: (...args: any[]) => AsyncGenerator<PhotonYield, any, any>, mockParams?: any): Promise<ExtractedYield[]>;
187
- /**
188
- * Create an input provider from pre-provided values
189
- * Throws if a required value is missing
580
+ * This is used for REST API schema generation - each ask becomes
581
+ * an optional request parameter.
582
+ *
583
+ * Note: Only extracts asks reachable with default/empty inputs.
584
+ * Conditional asks may not be discovered.
585
+ *
586
+ * @example
587
+ * const asks = await extractAsks(Photon.prototype.connect, { ip: '' });
588
+ * // Returns: [{ id: 'pairing_code', type: 'text', message: '...' }]
589
+ * // These become optional query/body params in REST API
190
590
  */
191
- export declare function createPrefilledProvider(inputs: Record<string, any>): InputProvider;
591
+ export declare function extractAsks(generatorFn: (...args: any[]) => AsyncGenerator<PhotonYield, any, any>, mockParams?: any): Promise<ExtractedAsk[]>;
192
592
  /**
193
- * Error thrown when input is needed but not available
194
- * Runtimes can catch this to return appropriate responses
593
+ * Error thrown when input is required but not available.
594
+ *
595
+ * REST APIs can catch this to return a continuation response.
596
+ *
597
+ * @example
598
+ * try {
599
+ * await executeGenerator(gen, { inputProvider: createPrefilledProvider({}) });
600
+ * } catch (e) {
601
+ * if (e instanceof NeedsInputError) {
602
+ * return {
603
+ * status: 'awaiting_input',
604
+ * ask: e.ask,
605
+ * continuation_id: saveContinuation(gen)
606
+ * };
607
+ * }
608
+ * }
195
609
  */
196
610
  export declare class NeedsInputError extends Error {
197
- readonly yielded: PhotonYield;
198
- constructor(yielded: PhotonYield);
611
+ readonly ask: AskYield;
612
+ constructor(ask: AskYield);
199
613
  }
200
614
  /**
201
- * Wrap a regular async function to behave like a generator
202
- * Useful for uniform handling in runtimes
615
+ * Create an input provider from pre-provided values.
616
+ * Throws NeedsInputError if a required value is missing.
617
+ *
618
+ * Use for REST APIs where all inputs are provided upfront.
619
+ *
620
+ * @example
621
+ * const provider = createPrefilledProvider({
622
+ * name: 'John',
623
+ * confirmed: true
624
+ * });
625
+ */
626
+ export declare function createPrefilledProvider(inputs: Record<string, any>): InputProvider;
627
+ /**
628
+ * Wrap a regular async function to behave like a generator.
629
+ * Useful for uniform handling in runtimes.
630
+ *
631
+ * @example
632
+ * const gen = wrapAsGenerator(() => photon.simpleMethod(params));
633
+ * const result = await executeGenerator(gen, config);
203
634
  */
204
635
  export declare function wrapAsGenerator<T>(asyncFn: () => Promise<T>): AsyncGenerator<never, T, unknown>;
636
+ /**
637
+ * @deprecated Use AskYield instead
638
+ */
639
+ export type PromptYield = AskText | AskPassword;
640
+ /**
641
+ * @deprecated Use AskConfirm instead
642
+ */
643
+ export type ConfirmYield = AskConfirm;
644
+ /**
645
+ * @deprecated Use AskSelect instead
646
+ */
647
+ export type SelectYield = AskSelect;
648
+ /**
649
+ * @deprecated Use EmitProgress instead
650
+ */
651
+ export type ProgressYield = EmitProgress;
652
+ /**
653
+ * @deprecated Use EmitStream instead
654
+ */
655
+ export type StreamYield = EmitStream;
656
+ /**
657
+ * @deprecated Use EmitLog instead
658
+ */
659
+ export type LogYield = EmitLog;
660
+ /**
661
+ * @deprecated Use isAskYield instead
662
+ */
663
+ export declare const isInputYield: typeof isAskYield;
664
+ /**
665
+ * @deprecated Use isEmitYield instead
666
+ */
667
+ export declare function isProgressYield(y: PhotonYield): y is EmitProgress;
668
+ /**
669
+ * @deprecated Use isEmitYield instead
670
+ */
671
+ export declare function isStreamYield(y: PhotonYield): y is EmitStream;
672
+ /**
673
+ * @deprecated Use isEmitYield instead
674
+ */
675
+ export declare function isLogYield(y: PhotonYield): y is EmitLog;
676
+ /**
677
+ * @deprecated Use extractAsks instead
678
+ */
679
+ export declare const extractYields: typeof extractAsks;
680
+ /**
681
+ * @deprecated Use ExtractedAsk instead
682
+ */
683
+ export type ExtractedYield = ExtractedAsk;
684
+ export {};
205
685
  //# sourceMappingURL=generator.d.ts.map