@d34dman/flowdrop 0.0.37 → 0.0.39
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/LICENSE +21 -0
- package/dist/components/NodeSidebar.svelte +1 -0
- package/dist/components/form/FormCodeEditor.svelte +6 -1
- package/dist/components/interrupt/ChoicePrompt.svelte +389 -0
- package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/FormPrompt.svelte +223 -0
- package/dist/components/interrupt/FormPrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/InterruptBubble.svelte +621 -0
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +16 -0
- package/dist/components/interrupt/TextInputPrompt.svelte +333 -0
- package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/index.d.ts +13 -0
- package/dist/components/interrupt/index.js +15 -0
- package/dist/components/nodes/GatewayNode.svelte +1 -3
- package/dist/components/nodes/IdeaNode.svelte +30 -35
- package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SimpleNode.svelte +1 -3
- package/dist/components/nodes/TerminalNode.svelte +1 -3
- package/dist/components/nodes/ToolNode.svelte +2 -2
- package/dist/components/nodes/WorkflowNode.svelte +1 -3
- package/dist/components/playground/ChatPanel.svelte +144 -7
- package/dist/components/playground/ChatPanel.svelte.d.ts +2 -0
- package/dist/components/playground/MessageBubble.svelte +1 -3
- package/dist/components/playground/Playground.svelte +50 -5
- package/dist/components/playground/PlaygroundModal.svelte +8 -7
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
- package/dist/config/endpoints.d.ts +12 -0
- package/dist/config/endpoints.js +7 -0
- package/dist/playground/index.d.ts +5 -0
- package/dist/playground/index.js +21 -0
- package/dist/playground/mount.d.ts +3 -3
- package/dist/playground/mount.js +30 -22
- package/dist/services/interruptService.d.ts +133 -0
- package/dist/services/interruptService.js +279 -0
- package/dist/stores/interruptStore.d.ts +200 -0
- package/dist/stores/interruptStore.js +424 -0
- package/dist/stores/playgroundStore.d.ts +11 -1
- package/dist/stores/playgroundStore.js +34 -0
- package/dist/styles/base.css +89 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interrupt.d.ts +305 -0
- package/dist/types/interrupt.js +126 -0
- package/dist/types/interruptState.d.ts +211 -0
- package/dist/types/interruptState.js +308 -0
- package/dist/utils/colors.js +1 -0
- package/dist/utils/connections.js +2 -2
- package/dist/utils/icons.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interrupt Types for Human-in-the-Loop (HITL) Support
|
|
3
|
+
*
|
|
4
|
+
* TypeScript types for workflow interrupts that pause execution
|
|
5
|
+
* and request user input before continuing.
|
|
6
|
+
*
|
|
7
|
+
* @module types/interrupt
|
|
8
|
+
*/
|
|
9
|
+
import type { ConfigSchema } from './index.js';
|
|
10
|
+
export type { InterruptState, IdleState, SubmittingState, ResolvedState, CancelledState, ErrorState, InterruptAction, SubmitAction, CancelAction, SuccessAction, FailureAction, RetryAction, ResetAction, TransitionResult } from './interruptState.js';
|
|
11
|
+
export { initialState, transition, isTerminalState, isSubmitting, hasError, canSubmit, getErrorMessage, getResolvedValue, toLegacyStatus } from './interruptState.js';
|
|
12
|
+
/**
|
|
13
|
+
* Types of interrupts supported by the system
|
|
14
|
+
*
|
|
15
|
+
* - `confirmation`: Simple Yes/No prompt
|
|
16
|
+
* - `choice`: Single or multiple option selection
|
|
17
|
+
* - `text`: Free-form text input
|
|
18
|
+
* - `form`: JSON Schema-based form
|
|
19
|
+
*/
|
|
20
|
+
export type InterruptType = 'confirmation' | 'choice' | 'text' | 'form';
|
|
21
|
+
/**
|
|
22
|
+
* Status of an interrupt request
|
|
23
|
+
*
|
|
24
|
+
* - `pending`: Awaiting user response
|
|
25
|
+
* - `resolved`: User has provided a response
|
|
26
|
+
* - `cancelled`: User or system cancelled the interrupt
|
|
27
|
+
* - `expired`: Interrupt timed out without response
|
|
28
|
+
*/
|
|
29
|
+
export type InterruptStatus = 'pending' | 'resolved' | 'cancelled' | 'expired';
|
|
30
|
+
/**
|
|
31
|
+
* Choice option for choice-type interrupts
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const option: InterruptChoice = {
|
|
36
|
+
* value: "high",
|
|
37
|
+
* label: "High Priority",
|
|
38
|
+
* description: "Process immediately"
|
|
39
|
+
* };
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export interface InterruptChoice {
|
|
43
|
+
/** Unique value identifier for this option */
|
|
44
|
+
value: string;
|
|
45
|
+
/** Display label for the option */
|
|
46
|
+
label: string;
|
|
47
|
+
/** Optional description providing more context */
|
|
48
|
+
description?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Configuration for confirmation-type interrupts
|
|
52
|
+
*/
|
|
53
|
+
export interface ConfirmationConfig {
|
|
54
|
+
/** The confirmation message/question to display */
|
|
55
|
+
message: string;
|
|
56
|
+
/** Label for the confirm/yes button */
|
|
57
|
+
confirmLabel?: string;
|
|
58
|
+
/** Label for the cancel/no button */
|
|
59
|
+
cancelLabel?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Configuration for choice-type interrupts
|
|
63
|
+
*/
|
|
64
|
+
export interface ChoiceConfig {
|
|
65
|
+
/** The prompt message to display */
|
|
66
|
+
message: string;
|
|
67
|
+
/** Available options to choose from */
|
|
68
|
+
options: InterruptChoice[];
|
|
69
|
+
/** Whether multiple selections are allowed */
|
|
70
|
+
multiple?: boolean;
|
|
71
|
+
/** Minimum number of selections required (for multiple mode) */
|
|
72
|
+
minSelections?: number;
|
|
73
|
+
/** Maximum number of selections allowed (for multiple mode) */
|
|
74
|
+
maxSelections?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Configuration for text-type interrupts
|
|
78
|
+
*/
|
|
79
|
+
export interface TextConfig {
|
|
80
|
+
/** The prompt message to display */
|
|
81
|
+
message: string;
|
|
82
|
+
/** Placeholder text for the input field */
|
|
83
|
+
placeholder?: string;
|
|
84
|
+
/** Whether to show a multiline text area */
|
|
85
|
+
multiline?: boolean;
|
|
86
|
+
/** Minimum text length required */
|
|
87
|
+
minLength?: number;
|
|
88
|
+
/** Maximum text length allowed */
|
|
89
|
+
maxLength?: number;
|
|
90
|
+
/** Default value to pre-fill */
|
|
91
|
+
defaultValue?: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Configuration for form-type interrupts
|
|
95
|
+
*/
|
|
96
|
+
export interface FormConfig {
|
|
97
|
+
/** The prompt message to display */
|
|
98
|
+
message: string;
|
|
99
|
+
/** JSON Schema defining the form fields */
|
|
100
|
+
schema: ConfigSchema;
|
|
101
|
+
/** Default values for form fields */
|
|
102
|
+
defaultValues?: Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Union type for interrupt-specific configuration
|
|
106
|
+
*/
|
|
107
|
+
export type InterruptConfig = ConfirmationConfig | ChoiceConfig | TextConfig | FormConfig;
|
|
108
|
+
/**
|
|
109
|
+
* Core interrupt data structure
|
|
110
|
+
*
|
|
111
|
+
* Represents a pending or resolved interrupt request from the workflow.
|
|
112
|
+
* Includes a state machine for tracking the interaction state.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const interrupt: Interrupt = {
|
|
117
|
+
* id: "int-123",
|
|
118
|
+
* type: "confirmation",
|
|
119
|
+
* status: "pending",
|
|
120
|
+
* message: "Send email to John?",
|
|
121
|
+
* nodeId: "node-456",
|
|
122
|
+
* executionId: "exec-789",
|
|
123
|
+
* sessionId: "sess-abc",
|
|
124
|
+
* createdAt: "2024-01-20T10:00:00Z",
|
|
125
|
+
* allowCancel: true,
|
|
126
|
+
* config: {
|
|
127
|
+
* message: "Send email to John?",
|
|
128
|
+
* confirmLabel: "Send",
|
|
129
|
+
* cancelLabel: "Don't Send"
|
|
130
|
+
* },
|
|
131
|
+
* state: { status: "idle" }
|
|
132
|
+
* };
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export interface Interrupt {
|
|
136
|
+
/** Unique identifier for the interrupt */
|
|
137
|
+
id: string;
|
|
138
|
+
/** Type of interrupt (confirmation, choice, text, form) */
|
|
139
|
+
type: InterruptType;
|
|
140
|
+
/**
|
|
141
|
+
* Current status of the interrupt (legacy field)
|
|
142
|
+
* @deprecated Use `state` for more detailed status tracking
|
|
143
|
+
*/
|
|
144
|
+
status: InterruptStatus;
|
|
145
|
+
/** Primary message/prompt to display */
|
|
146
|
+
message: string;
|
|
147
|
+
/** ID of the node that triggered the interrupt */
|
|
148
|
+
nodeId?: string;
|
|
149
|
+
/** ID of the workflow execution */
|
|
150
|
+
executionId?: string;
|
|
151
|
+
/** ID of the playground session (if applicable) */
|
|
152
|
+
sessionId?: string;
|
|
153
|
+
/** ID of the pipeline (if applicable) */
|
|
154
|
+
pipelineId?: string;
|
|
155
|
+
/** ID of the associated message in the chat flow */
|
|
156
|
+
messageId?: string;
|
|
157
|
+
/** Timestamp when the interrupt was created (ISO 8601) */
|
|
158
|
+
createdAt: string;
|
|
159
|
+
/** Timestamp when the interrupt was resolved (ISO 8601) */
|
|
160
|
+
resolvedAt?: string;
|
|
161
|
+
/** Timestamp when the interrupt expires (ISO 8601) */
|
|
162
|
+
expiresAt?: string;
|
|
163
|
+
/** Whether the user can cancel/dismiss this interrupt */
|
|
164
|
+
allowCancel: boolean;
|
|
165
|
+
/** Type-specific configuration */
|
|
166
|
+
config: InterruptConfig;
|
|
167
|
+
/** The user's response value (when resolved) */
|
|
168
|
+
responseValue?: unknown;
|
|
169
|
+
/** Additional metadata from the backend */
|
|
170
|
+
metadata?: Record<string, unknown>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Payload for resolving an interrupt
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* // Confirmation response
|
|
178
|
+
* const resolution: InterruptResolution = {
|
|
179
|
+
* value: true // or false
|
|
180
|
+
* };
|
|
181
|
+
*
|
|
182
|
+
* // Choice response (single)
|
|
183
|
+
* const resolution: InterruptResolution = {
|
|
184
|
+
* value: "option_a"
|
|
185
|
+
* };
|
|
186
|
+
*
|
|
187
|
+
* // Choice response (multiple)
|
|
188
|
+
* const resolution: InterruptResolution = {
|
|
189
|
+
* value: ["option_a", "option_b"]
|
|
190
|
+
* };
|
|
191
|
+
*
|
|
192
|
+
* // Text response
|
|
193
|
+
* const resolution: InterruptResolution = {
|
|
194
|
+
* value: "User entered text"
|
|
195
|
+
* };
|
|
196
|
+
*
|
|
197
|
+
* // Form response
|
|
198
|
+
* const resolution: InterruptResolution = {
|
|
199
|
+
* value: { name: "John", email: "john@example.com" }
|
|
200
|
+
* };
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
export interface InterruptResolution {
|
|
204
|
+
/** The user's response value */
|
|
205
|
+
value: unknown;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* API response for interrupt operations
|
|
209
|
+
*/
|
|
210
|
+
export interface InterruptApiResponse<T = Interrupt> {
|
|
211
|
+
/** Whether the request was successful */
|
|
212
|
+
success: boolean;
|
|
213
|
+
/** Response data */
|
|
214
|
+
data?: T;
|
|
215
|
+
/** Error message if unsuccessful */
|
|
216
|
+
error?: string;
|
|
217
|
+
/** Human-readable message */
|
|
218
|
+
message?: string;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Response type for listing interrupts
|
|
222
|
+
*/
|
|
223
|
+
export type InterruptListResponse = InterruptApiResponse<Interrupt[]>;
|
|
224
|
+
/**
|
|
225
|
+
* Response type for single interrupt operations
|
|
226
|
+
*/
|
|
227
|
+
export type InterruptResponse = InterruptApiResponse<Interrupt>;
|
|
228
|
+
/**
|
|
229
|
+
* Message metadata structure for interrupt detection
|
|
230
|
+
*
|
|
231
|
+
* When a message contains this metadata type, it indicates
|
|
232
|
+
* an interrupt request that should be rendered inline.
|
|
233
|
+
*/
|
|
234
|
+
export interface InterruptMessageMetadata {
|
|
235
|
+
/** Indicates this is an interrupt request */
|
|
236
|
+
type: 'interrupt_request';
|
|
237
|
+
/** The interrupt ID */
|
|
238
|
+
interrupt_id: string;
|
|
239
|
+
/** Type of interrupt */
|
|
240
|
+
interrupt_type: InterruptType;
|
|
241
|
+
/** JSON Schema for form-type interrupts */
|
|
242
|
+
schema?: ConfigSchema;
|
|
243
|
+
/** Options for choice-type interrupts */
|
|
244
|
+
options?: InterruptChoice[];
|
|
245
|
+
/** Default value for pre-filling */
|
|
246
|
+
default_value?: unknown;
|
|
247
|
+
/** Response value when interrupt has been resolved */
|
|
248
|
+
response_value?: unknown;
|
|
249
|
+
/** Node ID that triggered the interrupt */
|
|
250
|
+
node_id?: string;
|
|
251
|
+
/** Execution ID */
|
|
252
|
+
execution_id?: string;
|
|
253
|
+
/** Whether cancel is allowed */
|
|
254
|
+
allow_cancel?: boolean;
|
|
255
|
+
/** Labels for confirmation type */
|
|
256
|
+
confirm_label?: string;
|
|
257
|
+
cancel_label?: string;
|
|
258
|
+
/** Text input configuration */
|
|
259
|
+
placeholder?: string;
|
|
260
|
+
multiline?: boolean;
|
|
261
|
+
min_length?: number;
|
|
262
|
+
max_length?: number;
|
|
263
|
+
/** Choice configuration */
|
|
264
|
+
multiple?: boolean;
|
|
265
|
+
min_selections?: number;
|
|
266
|
+
max_selections?: number;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Type guard to check if message metadata indicates an interrupt
|
|
270
|
+
*
|
|
271
|
+
* @param metadata - Message metadata to check
|
|
272
|
+
* @returns True if the metadata indicates an interrupt request
|
|
273
|
+
*/
|
|
274
|
+
export declare function isInterruptMetadata(metadata: Record<string, unknown> | undefined): boolean;
|
|
275
|
+
/**
|
|
276
|
+
* Safely extract interrupt metadata from a generic record
|
|
277
|
+
*
|
|
278
|
+
* @param metadata - The metadata record to extract from
|
|
279
|
+
* @returns The interrupt metadata if valid, or null
|
|
280
|
+
*/
|
|
281
|
+
export declare function extractInterruptMetadata(metadata: Record<string, unknown> | undefined): InterruptMessageMetadata | null;
|
|
282
|
+
/**
|
|
283
|
+
* Convert interrupt message metadata to a full Interrupt object
|
|
284
|
+
*
|
|
285
|
+
* @param metadata - The interrupt message metadata
|
|
286
|
+
* @param messageId - The ID of the message containing the interrupt
|
|
287
|
+
* @param content - The message content (used as the interrupt message)
|
|
288
|
+
* @returns A fully populated Interrupt object
|
|
289
|
+
*/
|
|
290
|
+
export declare function metadataToInterrupt(metadata: InterruptMessageMetadata, messageId: string, content: string): Interrupt;
|
|
291
|
+
/**
|
|
292
|
+
* Configuration options for interrupt polling
|
|
293
|
+
*/
|
|
294
|
+
export interface InterruptPollingConfig {
|
|
295
|
+
/** Whether to enable dedicated interrupt polling */
|
|
296
|
+
enabled: boolean;
|
|
297
|
+
/** Polling interval in milliseconds */
|
|
298
|
+
interval?: number;
|
|
299
|
+
/** Maximum polling backoff interval in milliseconds */
|
|
300
|
+
maxBackoff?: number;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Default interrupt polling configuration
|
|
304
|
+
*/
|
|
305
|
+
export declare const defaultInterruptPollingConfig: InterruptPollingConfig;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interrupt Types for Human-in-the-Loop (HITL) Support
|
|
3
|
+
*
|
|
4
|
+
* TypeScript types for workflow interrupts that pause execution
|
|
5
|
+
* and request user input before continuing.
|
|
6
|
+
*
|
|
7
|
+
* @module types/interrupt
|
|
8
|
+
*/
|
|
9
|
+
export { initialState, transition, isTerminalState, isSubmitting, hasError, canSubmit, getErrorMessage, getResolvedValue, toLegacyStatus } from './interruptState.js';
|
|
10
|
+
/**
|
|
11
|
+
* Type guard to check if message metadata indicates an interrupt
|
|
12
|
+
*
|
|
13
|
+
* @param metadata - Message metadata to check
|
|
14
|
+
* @returns True if the metadata indicates an interrupt request
|
|
15
|
+
*/
|
|
16
|
+
export function isInterruptMetadata(metadata) {
|
|
17
|
+
return (metadata !== undefined &&
|
|
18
|
+
metadata.type === 'interrupt_request' &&
|
|
19
|
+
typeof metadata.interrupt_id === 'string');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Safely extract interrupt metadata from a generic record
|
|
23
|
+
*
|
|
24
|
+
* @param metadata - The metadata record to extract from
|
|
25
|
+
* @returns The interrupt metadata if valid, or null
|
|
26
|
+
*/
|
|
27
|
+
export function extractInterruptMetadata(metadata) {
|
|
28
|
+
if (!isInterruptMetadata(metadata)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
// Manually construct the typed object from the validated metadata
|
|
32
|
+
return {
|
|
33
|
+
type: 'interrupt_request',
|
|
34
|
+
interrupt_id: metadata.interrupt_id,
|
|
35
|
+
interrupt_type: metadata.interrupt_type,
|
|
36
|
+
schema: metadata.schema,
|
|
37
|
+
options: metadata.options,
|
|
38
|
+
default_value: metadata.default_value,
|
|
39
|
+
response_value: metadata.response_value,
|
|
40
|
+
node_id: metadata.node_id,
|
|
41
|
+
execution_id: metadata.execution_id,
|
|
42
|
+
allow_cancel: metadata.allow_cancel,
|
|
43
|
+
confirm_label: metadata.confirm_label,
|
|
44
|
+
cancel_label: metadata.cancel_label,
|
|
45
|
+
placeholder: metadata.placeholder,
|
|
46
|
+
multiline: metadata.multiline,
|
|
47
|
+
min_length: metadata.min_length,
|
|
48
|
+
max_length: metadata.max_length,
|
|
49
|
+
multiple: metadata.multiple,
|
|
50
|
+
min_selections: metadata.min_selections,
|
|
51
|
+
max_selections: metadata.max_selections
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Convert interrupt message metadata to a full Interrupt object
|
|
56
|
+
*
|
|
57
|
+
* @param metadata - The interrupt message metadata
|
|
58
|
+
* @param messageId - The ID of the message containing the interrupt
|
|
59
|
+
* @param content - The message content (used as the interrupt message)
|
|
60
|
+
* @returns A fully populated Interrupt object
|
|
61
|
+
*/
|
|
62
|
+
export function metadataToInterrupt(metadata, messageId, content) {
|
|
63
|
+
const baseInterrupt = {
|
|
64
|
+
id: metadata.interrupt_id,
|
|
65
|
+
type: metadata.interrupt_type,
|
|
66
|
+
status: 'pending',
|
|
67
|
+
message: content,
|
|
68
|
+
nodeId: metadata.node_id,
|
|
69
|
+
executionId: metadata.execution_id,
|
|
70
|
+
messageId,
|
|
71
|
+
createdAt: new Date().toISOString(),
|
|
72
|
+
allowCancel: metadata.allow_cancel ?? true,
|
|
73
|
+
config: buildInterruptConfig(metadata, content)
|
|
74
|
+
};
|
|
75
|
+
return baseInterrupt;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build the type-specific config from message metadata
|
|
79
|
+
*
|
|
80
|
+
* @param metadata - The interrupt message metadata
|
|
81
|
+
* @param message - The interrupt message content
|
|
82
|
+
* @returns Type-specific interrupt configuration
|
|
83
|
+
*/
|
|
84
|
+
function buildInterruptConfig(metadata, message) {
|
|
85
|
+
switch (metadata.interrupt_type) {
|
|
86
|
+
case 'confirmation':
|
|
87
|
+
return {
|
|
88
|
+
message,
|
|
89
|
+
confirmLabel: metadata.confirm_label ?? 'Yes',
|
|
90
|
+
cancelLabel: metadata.cancel_label ?? 'No'
|
|
91
|
+
};
|
|
92
|
+
case 'choice':
|
|
93
|
+
return {
|
|
94
|
+
message,
|
|
95
|
+
options: metadata.options ?? [],
|
|
96
|
+
multiple: metadata.multiple ?? false,
|
|
97
|
+
minSelections: metadata.min_selections,
|
|
98
|
+
maxSelections: metadata.max_selections
|
|
99
|
+
};
|
|
100
|
+
case 'text':
|
|
101
|
+
return {
|
|
102
|
+
message,
|
|
103
|
+
placeholder: metadata.placeholder,
|
|
104
|
+
multiline: metadata.multiline ?? false,
|
|
105
|
+
minLength: metadata.min_length,
|
|
106
|
+
maxLength: metadata.max_length,
|
|
107
|
+
defaultValue: metadata.default_value
|
|
108
|
+
};
|
|
109
|
+
case 'form':
|
|
110
|
+
return {
|
|
111
|
+
message,
|
|
112
|
+
schema: metadata.schema ?? { type: 'object', properties: {} },
|
|
113
|
+
defaultValues: metadata.default_value
|
|
114
|
+
};
|
|
115
|
+
default:
|
|
116
|
+
return { message };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Default interrupt polling configuration
|
|
121
|
+
*/
|
|
122
|
+
export const defaultInterruptPollingConfig = {
|
|
123
|
+
enabled: false,
|
|
124
|
+
interval: 2000,
|
|
125
|
+
maxBackoff: 10000
|
|
126
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interrupt State Machine
|
|
3
|
+
*
|
|
4
|
+
* Lightweight state machine pattern for interrupt handling.
|
|
5
|
+
* Ensures valid state transitions and prevents deadlocks.
|
|
6
|
+
*
|
|
7
|
+
* State Diagram:
|
|
8
|
+
* ```
|
|
9
|
+
* ┌─────────────┐
|
|
10
|
+
* │ idle │
|
|
11
|
+
* └──────┬──────┘
|
|
12
|
+
* │
|
|
13
|
+
* ┌──────────────┼──────────────┐
|
|
14
|
+
* │ submit │ cancel │
|
|
15
|
+
* ▼ │ ▼
|
|
16
|
+
* ┌─────────────┐ │ ┌─────────────┐
|
|
17
|
+
* │ submitting │ │ │ cancelled │
|
|
18
|
+
* └──────┬──────┘ │ └─────────────┘
|
|
19
|
+
* │ │
|
|
20
|
+
* ┌──────┴──────┐ │
|
|
21
|
+
* │ │ │
|
|
22
|
+
* ▼ success ▼ fail │
|
|
23
|
+
* ┌─────────┐ ┌─────────┐ │
|
|
24
|
+
* │resolved │ │ error │──┘ cancel
|
|
25
|
+
* └─────────┘ └────┬────┘
|
|
26
|
+
* │ retry
|
|
27
|
+
* ▼
|
|
28
|
+
* ┌─────────────┐
|
|
29
|
+
* │ submitting │
|
|
30
|
+
* └─────────────┘
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @module types/interruptState
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Idle state - waiting for user action
|
|
37
|
+
*/
|
|
38
|
+
export interface IdleState {
|
|
39
|
+
readonly status: 'idle';
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Submitting state - API call in progress
|
|
43
|
+
*/
|
|
44
|
+
export interface SubmittingState {
|
|
45
|
+
readonly status: 'submitting';
|
|
46
|
+
/** The value being submitted */
|
|
47
|
+
readonly pendingValue: unknown;
|
|
48
|
+
/** Whether this is a cancel operation */
|
|
49
|
+
readonly isCancelAction: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolved state - successfully completed
|
|
53
|
+
*/
|
|
54
|
+
export interface ResolvedState {
|
|
55
|
+
readonly status: 'resolved';
|
|
56
|
+
/** The submitted value */
|
|
57
|
+
readonly value: unknown;
|
|
58
|
+
/** Timestamp when resolved */
|
|
59
|
+
readonly resolvedAt: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Cancelled state - user cancelled
|
|
63
|
+
*/
|
|
64
|
+
export interface CancelledState {
|
|
65
|
+
readonly status: 'cancelled';
|
|
66
|
+
/** Timestamp when cancelled */
|
|
67
|
+
readonly cancelledAt: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Error state - submission failed, can retry
|
|
71
|
+
*/
|
|
72
|
+
export interface ErrorState {
|
|
73
|
+
readonly status: 'error';
|
|
74
|
+
/** The error message */
|
|
75
|
+
readonly error: string;
|
|
76
|
+
/** The value that failed to submit (for retry) */
|
|
77
|
+
readonly failedValue?: unknown;
|
|
78
|
+
/** Whether the failed action was a cancel */
|
|
79
|
+
readonly wasCancelAction: boolean;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Union of all possible interrupt states
|
|
83
|
+
*/
|
|
84
|
+
export type InterruptState = IdleState | SubmittingState | ResolvedState | CancelledState | ErrorState;
|
|
85
|
+
/**
|
|
86
|
+
* Submit action - user submits a value
|
|
87
|
+
*/
|
|
88
|
+
export interface SubmitAction {
|
|
89
|
+
readonly type: 'SUBMIT';
|
|
90
|
+
readonly value: unknown;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Cancel action - user cancels the interrupt
|
|
94
|
+
*/
|
|
95
|
+
export interface CancelAction {
|
|
96
|
+
readonly type: 'CANCEL';
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Success action - API call succeeded
|
|
100
|
+
*/
|
|
101
|
+
export interface SuccessAction {
|
|
102
|
+
readonly type: 'SUCCESS';
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Failure action - API call failed
|
|
106
|
+
*/
|
|
107
|
+
export interface FailureAction {
|
|
108
|
+
readonly type: 'FAILURE';
|
|
109
|
+
readonly error: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Retry action - retry after error
|
|
113
|
+
*/
|
|
114
|
+
export interface RetryAction {
|
|
115
|
+
readonly type: 'RETRY';
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Reset action - reset to idle state
|
|
119
|
+
*/
|
|
120
|
+
export interface ResetAction {
|
|
121
|
+
readonly type: 'RESET';
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Union of all possible actions
|
|
125
|
+
*/
|
|
126
|
+
export type InterruptAction = SubmitAction | CancelAction | SuccessAction | FailureAction | RetryAction | ResetAction;
|
|
127
|
+
/**
|
|
128
|
+
* Result of a state transition
|
|
129
|
+
*/
|
|
130
|
+
export interface TransitionResult {
|
|
131
|
+
/** The new state after transition */
|
|
132
|
+
state: InterruptState;
|
|
133
|
+
/** Whether the transition was valid */
|
|
134
|
+
valid: boolean;
|
|
135
|
+
/** Error message if transition was invalid */
|
|
136
|
+
error?: string;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Initial idle state
|
|
140
|
+
*/
|
|
141
|
+
export declare const initialState: IdleState;
|
|
142
|
+
/**
|
|
143
|
+
* Transition function for the interrupt state machine
|
|
144
|
+
*
|
|
145
|
+
* @param state - Current state
|
|
146
|
+
* @param action - Action to apply
|
|
147
|
+
* @returns New state after transition
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* let state = initialState;
|
|
152
|
+
*
|
|
153
|
+
* // User submits
|
|
154
|
+
* const result1 = transition(state, { type: "SUBMIT", value: true });
|
|
155
|
+
* if (result1.valid) state = result1.state;
|
|
156
|
+
*
|
|
157
|
+
* // API succeeds
|
|
158
|
+
* const result2 = transition(state, { type: "SUCCESS" });
|
|
159
|
+
* if (result2.valid) state = result2.state;
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export declare function transition(state: InterruptState, action: InterruptAction): TransitionResult;
|
|
163
|
+
/**
|
|
164
|
+
* Check if the interrupt is in a terminal state (resolved or cancelled)
|
|
165
|
+
*
|
|
166
|
+
* @param state - The interrupt state
|
|
167
|
+
* @returns True if the interrupt is finished
|
|
168
|
+
*/
|
|
169
|
+
export declare function isTerminalState(state: InterruptState): boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Check if the interrupt is currently submitting
|
|
172
|
+
*
|
|
173
|
+
* @param state - The interrupt state
|
|
174
|
+
* @returns True if submitting
|
|
175
|
+
*/
|
|
176
|
+
export declare function isSubmitting(state: InterruptState): boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Check if the interrupt has an error
|
|
179
|
+
*
|
|
180
|
+
* @param state - The interrupt state
|
|
181
|
+
* @returns True if in error state
|
|
182
|
+
*/
|
|
183
|
+
export declare function hasError(state: InterruptState): boolean;
|
|
184
|
+
/**
|
|
185
|
+
* Check if the interrupt can accept user input
|
|
186
|
+
*
|
|
187
|
+
* @param state - The interrupt state
|
|
188
|
+
* @returns True if idle or error (can submit)
|
|
189
|
+
*/
|
|
190
|
+
export declare function canSubmit(state: InterruptState): boolean;
|
|
191
|
+
/**
|
|
192
|
+
* Get the error message if in error state
|
|
193
|
+
*
|
|
194
|
+
* @param state - The interrupt state
|
|
195
|
+
* @returns Error message or undefined
|
|
196
|
+
*/
|
|
197
|
+
export declare function getErrorMessage(state: InterruptState): string | undefined;
|
|
198
|
+
/**
|
|
199
|
+
* Get the resolved value if in resolved state
|
|
200
|
+
*
|
|
201
|
+
* @param state - The interrupt state
|
|
202
|
+
* @returns Resolved value or undefined
|
|
203
|
+
*/
|
|
204
|
+
export declare function getResolvedValue(state: InterruptState): unknown;
|
|
205
|
+
/**
|
|
206
|
+
* Map InterruptState status to legacy InterruptStatus for backward compatibility
|
|
207
|
+
*
|
|
208
|
+
* @param state - The interrupt state
|
|
209
|
+
* @returns Legacy status string
|
|
210
|
+
*/
|
|
211
|
+
export declare function toLegacyStatus(state: InterruptState): 'pending' | 'resolved' | 'cancelled' | 'expired';
|