@d34dman/flowdrop 0.0.30 → 0.0.32
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/components/App.svelte +54 -6
- package/dist/components/NodeSidebar.svelte +1 -1
- package/dist/components/SchemaForm.svelte +14 -14
- package/dist/components/SchemaForm.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldLight.svelte +66 -66
- package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
- package/dist/components/form/types.d.ts +1 -1
- package/dist/components/playground/ChatPanel.svelte +523 -0
- package/dist/components/playground/ChatPanel.svelte.d.ts +20 -0
- package/dist/components/playground/ExecutionLogs.svelte +486 -0
- package/dist/components/playground/ExecutionLogs.svelte.d.ts +14 -0
- package/dist/components/playground/InputCollector.svelte +444 -0
- package/dist/components/playground/InputCollector.svelte.d.ts +16 -0
- package/dist/components/playground/MessageBubble.svelte +398 -0
- package/dist/components/playground/MessageBubble.svelte.d.ts +15 -0
- package/dist/components/playground/Playground.svelte +861 -0
- package/dist/components/playground/Playground.svelte.d.ts +25 -0
- package/dist/components/playground/PlaygroundModal.svelte +220 -0
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +25 -0
- package/dist/components/playground/SessionManager.svelte +537 -0
- package/dist/components/playground/SessionManager.svelte.d.ts +20 -0
- package/dist/config/endpoints.d.ts +16 -0
- package/dist/config/endpoints.js +9 -0
- package/dist/core/index.d.ts +25 -23
- package/dist/core/index.js +13 -12
- package/dist/display/index.d.ts +2 -2
- package/dist/display/index.js +2 -2
- package/dist/editor/index.d.ts +58 -49
- package/dist/editor/index.js +53 -42
- package/dist/form/code.d.ts +4 -4
- package/dist/form/code.js +11 -11
- package/dist/form/fieldRegistry.d.ts +2 -2
- package/dist/form/fieldRegistry.js +8 -10
- package/dist/form/full.d.ts +5 -5
- package/dist/form/full.js +7 -7
- package/dist/form/index.d.ts +16 -16
- package/dist/form/index.js +14 -14
- package/dist/form/markdown.d.ts +3 -3
- package/dist/form/markdown.js +6 -6
- package/dist/index.d.ts +6 -4
- package/dist/index.js +9 -4
- package/dist/playground/index.d.ts +125 -0
- package/dist/playground/index.js +147 -0
- package/dist/playground/mount.d.ts +184 -0
- package/dist/playground/mount.js +209 -0
- package/dist/services/playgroundService.d.ts +129 -0
- package/dist/services/playgroundService.js +317 -0
- package/dist/stores/playgroundStore.d.ts +199 -0
- package/dist/stores/playgroundStore.js +350 -0
- package/dist/types/playground.d.ts +230 -0
- package/dist/types/playground.js +28 -0
- package/dist/utils/colors.js +4 -4
- package/package.json +6 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playground Mount Functions
|
|
3
|
+
*
|
|
4
|
+
* Provides mount/unmount functions for integrating the Playground component
|
|
5
|
+
* into any web application. Particularly useful for integration with
|
|
6
|
+
* vanilla JS, Drupal, WordPress, or other frameworks.
|
|
7
|
+
*
|
|
8
|
+
* @module playground/mount
|
|
9
|
+
*
|
|
10
|
+
* @example Basic usage in vanilla JavaScript:
|
|
11
|
+
* ```javascript
|
|
12
|
+
* const app = await FlowDrop.mountPlayground(
|
|
13
|
+
* document.getElementById("playground-container"),
|
|
14
|
+
* {
|
|
15
|
+
* workflowId: "wf-123",
|
|
16
|
+
* endpointConfig: FlowDrop.createEndpointConfig("/api/flowdrop"),
|
|
17
|
+
* mode: "standalone"
|
|
18
|
+
* }
|
|
19
|
+
* );
|
|
20
|
+
*
|
|
21
|
+
* // Later, to cleanup:
|
|
22
|
+
* app.destroy();
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example Drupal integration:
|
|
26
|
+
* ```javascript
|
|
27
|
+
* (function (Drupal, FlowDrop) {
|
|
28
|
+
* Drupal.behaviors.flowdropPlayground = {
|
|
29
|
+
* attach: function (context, settings) {
|
|
30
|
+
* const container = document.getElementById("playground-container");
|
|
31
|
+
* if (!container || container.dataset.initialized) return;
|
|
32
|
+
* container.dataset.initialized = "true";
|
|
33
|
+
*
|
|
34
|
+
* FlowDrop.mountPlayground(container, {
|
|
35
|
+
* workflowId: settings.flowdrop.workflowId,
|
|
36
|
+
* endpointConfig: FlowDrop.createEndpointConfig(settings.flowdrop.apiBaseUrl),
|
|
37
|
+
* mode: "standalone"
|
|
38
|
+
* }).then(function (app) {
|
|
39
|
+
* container._flowdropApp = app;
|
|
40
|
+
* });
|
|
41
|
+
* }
|
|
42
|
+
* };
|
|
43
|
+
* })(Drupal, window.FlowDrop);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
import { mount, unmount } from "svelte";
|
|
47
|
+
import Playground from "../components/playground/Playground.svelte";
|
|
48
|
+
import PlaygroundModal from "../components/playground/PlaygroundModal.svelte";
|
|
49
|
+
import { setEndpointConfig } from "../services/api.js";
|
|
50
|
+
import { playgroundService } from "../services/playgroundService.js";
|
|
51
|
+
import { currentSession, sessions, messages, playgroundActions } from "../stores/playgroundStore.js";
|
|
52
|
+
import { get } from "svelte/store";
|
|
53
|
+
/**
|
|
54
|
+
* Mount the Playground component in a container
|
|
55
|
+
*
|
|
56
|
+
* This function mounts the Playground Svelte component into a DOM container,
|
|
57
|
+
* enabling interactive workflow testing with a chat interface.
|
|
58
|
+
*
|
|
59
|
+
* @param container - DOM element to mount the playground into
|
|
60
|
+
* @param options - Configuration options for the playground
|
|
61
|
+
* @returns Promise resolving to a MountedPlayground instance
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* import { mountPlayground, createEndpointConfig } from "@d34dman/flowdrop/playground";
|
|
66
|
+
*
|
|
67
|
+
* const app = await mountPlayground(
|
|
68
|
+
* document.getElementById("playground"),
|
|
69
|
+
* {
|
|
70
|
+
* workflowId: "wf-123",
|
|
71
|
+
* endpointConfig: createEndpointConfig("/api/flowdrop"),
|
|
72
|
+
* mode: "standalone",
|
|
73
|
+
* config: {
|
|
74
|
+
* showTimestamps: true,
|
|
75
|
+
* autoScroll: true,
|
|
76
|
+
* pollingInterval: 1500
|
|
77
|
+
* }
|
|
78
|
+
* }
|
|
79
|
+
* );
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export async function mountPlayground(container, options) {
|
|
83
|
+
const { workflowId, workflow, mode = "standalone", initialSessionId, endpointConfig, config = {}, height = "100%", width = "100%", onClose } = options;
|
|
84
|
+
// Validate required parameters
|
|
85
|
+
if (!workflowId) {
|
|
86
|
+
throw new Error("workflowId is required for mountPlayground()");
|
|
87
|
+
}
|
|
88
|
+
if (!container) {
|
|
89
|
+
throw new Error("container element is required for mountPlayground()");
|
|
90
|
+
}
|
|
91
|
+
// Validate onClose for modal mode
|
|
92
|
+
if (mode === "modal" && !onClose) {
|
|
93
|
+
throw new Error("onClose callback is required for modal mode");
|
|
94
|
+
}
|
|
95
|
+
// Set endpoint configuration if provided
|
|
96
|
+
let finalEndpointConfig;
|
|
97
|
+
if (endpointConfig) {
|
|
98
|
+
// Merge with default configuration to ensure all required endpoints are present
|
|
99
|
+
const { defaultEndpointConfig } = await import("../config/endpoints.js");
|
|
100
|
+
finalEndpointConfig = {
|
|
101
|
+
...defaultEndpointConfig,
|
|
102
|
+
...endpointConfig,
|
|
103
|
+
endpoints: {
|
|
104
|
+
...defaultEndpointConfig.endpoints,
|
|
105
|
+
...endpointConfig.endpoints
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
setEndpointConfig(finalEndpointConfig);
|
|
109
|
+
}
|
|
110
|
+
// Handle modal mode differently
|
|
111
|
+
// For modal mode, PlaygroundModal creates its own backdrop, so we mount directly to body
|
|
112
|
+
// For other modes, use the provided container
|
|
113
|
+
let targetContainer = container;
|
|
114
|
+
if (mode === "modal") {
|
|
115
|
+
// For modal mode, create a container in the body
|
|
116
|
+
// PlaygroundModal will handle the backdrop itself
|
|
117
|
+
targetContainer = document.body;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Apply container styling for non-modal modes
|
|
121
|
+
container.style.height = height;
|
|
122
|
+
container.style.width = width;
|
|
123
|
+
}
|
|
124
|
+
// Mount the appropriate component
|
|
125
|
+
const svelteApp = mount(mode === "modal" ? PlaygroundModal : Playground, {
|
|
126
|
+
target: targetContainer,
|
|
127
|
+
props: mode === "modal"
|
|
128
|
+
? {
|
|
129
|
+
isOpen: true,
|
|
130
|
+
workflowId,
|
|
131
|
+
workflow,
|
|
132
|
+
initialSessionId,
|
|
133
|
+
endpointConfig: finalEndpointConfig,
|
|
134
|
+
config,
|
|
135
|
+
onClose: () => {
|
|
136
|
+
if (onClose) {
|
|
137
|
+
onClose();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
: {
|
|
142
|
+
workflowId,
|
|
143
|
+
workflow,
|
|
144
|
+
mode,
|
|
145
|
+
initialSessionId,
|
|
146
|
+
endpointConfig: finalEndpointConfig,
|
|
147
|
+
config,
|
|
148
|
+
onClose
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
// Store state for cleanup
|
|
152
|
+
const state = {
|
|
153
|
+
svelteApp,
|
|
154
|
+
container: targetContainer,
|
|
155
|
+
originalContainer: mode === "modal" ? container : undefined,
|
|
156
|
+
workflowId
|
|
157
|
+
};
|
|
158
|
+
// Create the mounted playground interface
|
|
159
|
+
const mountedPlayground = {
|
|
160
|
+
destroy: () => {
|
|
161
|
+
// Stop any active polling
|
|
162
|
+
playgroundService.stopPolling();
|
|
163
|
+
// Reset playground state
|
|
164
|
+
playgroundActions.reset();
|
|
165
|
+
// Unmount Svelte component
|
|
166
|
+
unmount(state.svelteApp);
|
|
167
|
+
},
|
|
168
|
+
getCurrentSession: () => {
|
|
169
|
+
return get(currentSession);
|
|
170
|
+
},
|
|
171
|
+
getSessions: () => {
|
|
172
|
+
return get(sessions);
|
|
173
|
+
},
|
|
174
|
+
getMessageCount: () => {
|
|
175
|
+
return get(messages).length;
|
|
176
|
+
},
|
|
177
|
+
isExecuting: () => {
|
|
178
|
+
return playgroundService.isPolling();
|
|
179
|
+
},
|
|
180
|
+
stopPolling: () => {
|
|
181
|
+
playgroundService.stopPolling();
|
|
182
|
+
},
|
|
183
|
+
reset: () => {
|
|
184
|
+
playgroundService.stopPolling();
|
|
185
|
+
playgroundActions.reset();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
return mountedPlayground;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Unmount a Playground instance
|
|
192
|
+
*
|
|
193
|
+
* Convenience function for destroying a mounted playground.
|
|
194
|
+
* Equivalent to calling `app.destroy()`.
|
|
195
|
+
*
|
|
196
|
+
* @param app - The mounted playground to unmount
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* const app = await mountPlayground(container, options);
|
|
201
|
+
* // ... later
|
|
202
|
+
* unmountPlayground(app);
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
export function unmountPlayground(app) {
|
|
206
|
+
if (app && typeof app.destroy === "function") {
|
|
207
|
+
app.destroy();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playground Service
|
|
3
|
+
*
|
|
4
|
+
* Handles API interactions for the Playground feature including
|
|
5
|
+
* session management, message handling, and polling for updates.
|
|
6
|
+
*
|
|
7
|
+
* @module services/playgroundService
|
|
8
|
+
*/
|
|
9
|
+
import type { PlaygroundSession, PlaygroundMessage, PlaygroundMessagesApiResponse } from '../types/playground.js';
|
|
10
|
+
/**
|
|
11
|
+
* Playground Service class
|
|
12
|
+
*
|
|
13
|
+
* Provides methods to interact with the playground API endpoints
|
|
14
|
+
* including session management, message handling, and polling.
|
|
15
|
+
*/
|
|
16
|
+
export declare class PlaygroundService {
|
|
17
|
+
private static instance;
|
|
18
|
+
private pollingInterval;
|
|
19
|
+
private pollingSessionId;
|
|
20
|
+
private currentBackoff;
|
|
21
|
+
private lastMessageTimestamp;
|
|
22
|
+
private constructor();
|
|
23
|
+
/**
|
|
24
|
+
* Get the singleton instance of PlaygroundService
|
|
25
|
+
*
|
|
26
|
+
* @returns The PlaygroundService singleton instance
|
|
27
|
+
*/
|
|
28
|
+
static getInstance(): PlaygroundService;
|
|
29
|
+
/**
|
|
30
|
+
* Get the endpoint configuration
|
|
31
|
+
*
|
|
32
|
+
* @throws Error if endpoint configuration is not set
|
|
33
|
+
* @returns The endpoint configuration
|
|
34
|
+
*/
|
|
35
|
+
private getConfig;
|
|
36
|
+
/**
|
|
37
|
+
* Generic API request helper
|
|
38
|
+
*
|
|
39
|
+
* @param url - The URL to fetch
|
|
40
|
+
* @param options - Fetch options
|
|
41
|
+
* @returns The parsed JSON response
|
|
42
|
+
*/
|
|
43
|
+
private request;
|
|
44
|
+
/**
|
|
45
|
+
* List all playground sessions for a workflow
|
|
46
|
+
*
|
|
47
|
+
* @param workflowId - The workflow UUID
|
|
48
|
+
* @param options - Optional pagination parameters
|
|
49
|
+
* @returns Array of playground sessions
|
|
50
|
+
*/
|
|
51
|
+
listSessions(workflowId: string, options?: {
|
|
52
|
+
limit?: number;
|
|
53
|
+
offset?: number;
|
|
54
|
+
}): Promise<PlaygroundSession[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Create a new playground session
|
|
57
|
+
*
|
|
58
|
+
* @param workflowId - The workflow UUID
|
|
59
|
+
* @param name - Optional session name
|
|
60
|
+
* @param metadata - Optional session metadata
|
|
61
|
+
* @returns The created session
|
|
62
|
+
*/
|
|
63
|
+
createSession(workflowId: string, name?: string, metadata?: Record<string, unknown>): Promise<PlaygroundSession>;
|
|
64
|
+
/**
|
|
65
|
+
* Get a playground session by ID
|
|
66
|
+
*
|
|
67
|
+
* @param sessionId - The session UUID
|
|
68
|
+
* @returns The session details
|
|
69
|
+
*/
|
|
70
|
+
getSession(sessionId: string): Promise<PlaygroundSession>;
|
|
71
|
+
/**
|
|
72
|
+
* Delete a playground session
|
|
73
|
+
*
|
|
74
|
+
* @param sessionId - The session UUID
|
|
75
|
+
*/
|
|
76
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Get messages from a playground session
|
|
79
|
+
*
|
|
80
|
+
* @param sessionId - The session UUID
|
|
81
|
+
* @param since - Optional timestamp to fetch only newer messages (ISO 8601)
|
|
82
|
+
* @param limit - Maximum number of messages to return
|
|
83
|
+
* @returns Messages and session status
|
|
84
|
+
*/
|
|
85
|
+
getMessages(sessionId: string, since?: string, limit?: number): Promise<PlaygroundMessagesApiResponse>;
|
|
86
|
+
/**
|
|
87
|
+
* Send a message to a playground session
|
|
88
|
+
*
|
|
89
|
+
* @param sessionId - The session UUID
|
|
90
|
+
* @param content - The message content
|
|
91
|
+
* @param inputs - Optional additional inputs for workflow nodes
|
|
92
|
+
* @returns The created message
|
|
93
|
+
*/
|
|
94
|
+
sendMessage(sessionId: string, content: string, inputs?: Record<string, unknown>): Promise<PlaygroundMessage>;
|
|
95
|
+
/**
|
|
96
|
+
* Stop execution in a playground session
|
|
97
|
+
*
|
|
98
|
+
* @param sessionId - The session UUID
|
|
99
|
+
*/
|
|
100
|
+
stopExecution(sessionId: string): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Start polling for new messages
|
|
103
|
+
*
|
|
104
|
+
* @param sessionId - The session UUID to poll
|
|
105
|
+
* @param callback - Callback function to handle new messages
|
|
106
|
+
* @param interval - Polling interval in milliseconds (default: 1500)
|
|
107
|
+
*/
|
|
108
|
+
startPolling(sessionId: string, callback: (response: PlaygroundMessagesApiResponse) => void, interval?: number): void;
|
|
109
|
+
/**
|
|
110
|
+
* Stop polling for messages
|
|
111
|
+
*/
|
|
112
|
+
stopPolling(): void;
|
|
113
|
+
/**
|
|
114
|
+
* Check if polling is active
|
|
115
|
+
*
|
|
116
|
+
* @returns True if polling is active
|
|
117
|
+
*/
|
|
118
|
+
isPolling(): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Get the current polling session ID
|
|
121
|
+
*
|
|
122
|
+
* @returns The session ID being polled, or null
|
|
123
|
+
*/
|
|
124
|
+
getPollingSessionId(): string | null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Export singleton instance
|
|
128
|
+
*/
|
|
129
|
+
export declare const playgroundService: PlaygroundService;
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playground Service
|
|
3
|
+
*
|
|
4
|
+
* Handles API interactions for the Playground feature including
|
|
5
|
+
* session management, message handling, and polling for updates.
|
|
6
|
+
*
|
|
7
|
+
* @module services/playgroundService
|
|
8
|
+
*/
|
|
9
|
+
import { buildEndpointUrl, getEndpointHeaders } from '../config/endpoints.js';
|
|
10
|
+
import { getEndpointConfig } from './api.js';
|
|
11
|
+
/**
|
|
12
|
+
* Default polling interval in milliseconds
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_POLLING_INTERVAL = 1500;
|
|
15
|
+
/**
|
|
16
|
+
* Maximum polling backoff interval in milliseconds
|
|
17
|
+
*/
|
|
18
|
+
const MAX_POLLING_BACKOFF = 10000;
|
|
19
|
+
/**
|
|
20
|
+
* Playground Service class
|
|
21
|
+
*
|
|
22
|
+
* Provides methods to interact with the playground API endpoints
|
|
23
|
+
* including session management, message handling, and polling.
|
|
24
|
+
*/
|
|
25
|
+
export class PlaygroundService {
|
|
26
|
+
static instance;
|
|
27
|
+
pollingInterval = null;
|
|
28
|
+
pollingSessionId = null;
|
|
29
|
+
currentBackoff = DEFAULT_POLLING_INTERVAL;
|
|
30
|
+
lastMessageTimestamp = null;
|
|
31
|
+
constructor() { }
|
|
32
|
+
/**
|
|
33
|
+
* Get the singleton instance of PlaygroundService
|
|
34
|
+
*
|
|
35
|
+
* @returns The PlaygroundService singleton instance
|
|
36
|
+
*/
|
|
37
|
+
static getInstance() {
|
|
38
|
+
if (!PlaygroundService.instance) {
|
|
39
|
+
PlaygroundService.instance = new PlaygroundService();
|
|
40
|
+
}
|
|
41
|
+
return PlaygroundService.instance;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the endpoint configuration
|
|
45
|
+
*
|
|
46
|
+
* @throws Error if endpoint configuration is not set
|
|
47
|
+
* @returns The endpoint configuration
|
|
48
|
+
*/
|
|
49
|
+
getConfig() {
|
|
50
|
+
const config = getEndpointConfig();
|
|
51
|
+
if (!config) {
|
|
52
|
+
throw new Error('Endpoint configuration not set. Call setEndpointConfig() first.');
|
|
53
|
+
}
|
|
54
|
+
return config;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Generic API request helper
|
|
58
|
+
*
|
|
59
|
+
* @param url - The URL to fetch
|
|
60
|
+
* @param options - Fetch options
|
|
61
|
+
* @returns The parsed JSON response
|
|
62
|
+
*/
|
|
63
|
+
async request(url, options = {}) {
|
|
64
|
+
const config = this.getConfig();
|
|
65
|
+
const headers = getEndpointHeaders(config, 'playground');
|
|
66
|
+
const response = await fetch(url, {
|
|
67
|
+
...options,
|
|
68
|
+
headers: {
|
|
69
|
+
...headers,
|
|
70
|
+
...options.headers
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
const errorData = await response.json().catch(() => ({}));
|
|
75
|
+
const errorMessage = errorData.error ||
|
|
76
|
+
errorData.message ||
|
|
77
|
+
`HTTP ${response.status}: ${response.statusText}`;
|
|
78
|
+
throw new Error(errorMessage);
|
|
79
|
+
}
|
|
80
|
+
return response.json();
|
|
81
|
+
}
|
|
82
|
+
// =========================================================================
|
|
83
|
+
// Session Management
|
|
84
|
+
// =========================================================================
|
|
85
|
+
/**
|
|
86
|
+
* List all playground sessions for a workflow
|
|
87
|
+
*
|
|
88
|
+
* @param workflowId - The workflow UUID
|
|
89
|
+
* @param options - Optional pagination parameters
|
|
90
|
+
* @returns Array of playground sessions
|
|
91
|
+
*/
|
|
92
|
+
async listSessions(workflowId, options) {
|
|
93
|
+
const config = this.getConfig();
|
|
94
|
+
let url = buildEndpointUrl(config, config.endpoints.playground.listSessions, {
|
|
95
|
+
id: workflowId
|
|
96
|
+
});
|
|
97
|
+
// Add query parameters
|
|
98
|
+
const params = new URLSearchParams();
|
|
99
|
+
if (options?.limit !== undefined) {
|
|
100
|
+
params.append('limit', options.limit.toString());
|
|
101
|
+
}
|
|
102
|
+
if (options?.offset !== undefined) {
|
|
103
|
+
params.append('offset', options.offset.toString());
|
|
104
|
+
}
|
|
105
|
+
const queryString = params.toString();
|
|
106
|
+
if (queryString) {
|
|
107
|
+
url = `${url}?${queryString}`;
|
|
108
|
+
}
|
|
109
|
+
const response = await this.request(url);
|
|
110
|
+
return response.data ?? [];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Create a new playground session
|
|
114
|
+
*
|
|
115
|
+
* @param workflowId - The workflow UUID
|
|
116
|
+
* @param name - Optional session name
|
|
117
|
+
* @param metadata - Optional session metadata
|
|
118
|
+
* @returns The created session
|
|
119
|
+
*/
|
|
120
|
+
async createSession(workflowId, name, metadata) {
|
|
121
|
+
const config = this.getConfig();
|
|
122
|
+
const url = buildEndpointUrl(config, config.endpoints.playground.createSession, {
|
|
123
|
+
id: workflowId
|
|
124
|
+
});
|
|
125
|
+
const response = await this.request(url, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
body: JSON.stringify({ name, metadata })
|
|
128
|
+
});
|
|
129
|
+
if (!response.data) {
|
|
130
|
+
throw new Error('Failed to create session: No data returned');
|
|
131
|
+
}
|
|
132
|
+
return response.data;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Get a playground session by ID
|
|
136
|
+
*
|
|
137
|
+
* @param sessionId - The session UUID
|
|
138
|
+
* @returns The session details
|
|
139
|
+
*/
|
|
140
|
+
async getSession(sessionId) {
|
|
141
|
+
const config = this.getConfig();
|
|
142
|
+
const url = buildEndpointUrl(config, config.endpoints.playground.getSession, {
|
|
143
|
+
sessionId
|
|
144
|
+
});
|
|
145
|
+
const response = await this.request(url);
|
|
146
|
+
if (!response.data) {
|
|
147
|
+
throw new Error('Session not found');
|
|
148
|
+
}
|
|
149
|
+
return response.data;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Delete a playground session
|
|
153
|
+
*
|
|
154
|
+
* @param sessionId - The session UUID
|
|
155
|
+
*/
|
|
156
|
+
async deleteSession(sessionId) {
|
|
157
|
+
const config = this.getConfig();
|
|
158
|
+
const url = buildEndpointUrl(config, config.endpoints.playground.deleteSession, {
|
|
159
|
+
sessionId
|
|
160
|
+
});
|
|
161
|
+
await this.request(url, {
|
|
162
|
+
method: 'DELETE'
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
// =========================================================================
|
|
166
|
+
// Message Handling
|
|
167
|
+
// =========================================================================
|
|
168
|
+
/**
|
|
169
|
+
* Get messages from a playground session
|
|
170
|
+
*
|
|
171
|
+
* @param sessionId - The session UUID
|
|
172
|
+
* @param since - Optional timestamp to fetch only newer messages (ISO 8601)
|
|
173
|
+
* @param limit - Maximum number of messages to return
|
|
174
|
+
* @returns Messages and session status
|
|
175
|
+
*/
|
|
176
|
+
async getMessages(sessionId, since, limit) {
|
|
177
|
+
const config = this.getConfig();
|
|
178
|
+
let url = buildEndpointUrl(config, config.endpoints.playground.getMessages, {
|
|
179
|
+
sessionId
|
|
180
|
+
});
|
|
181
|
+
// Add query parameters
|
|
182
|
+
const params = new URLSearchParams();
|
|
183
|
+
if (since) {
|
|
184
|
+
params.append('since', since);
|
|
185
|
+
}
|
|
186
|
+
if (limit !== undefined) {
|
|
187
|
+
params.append('limit', limit.toString());
|
|
188
|
+
}
|
|
189
|
+
const queryString = params.toString();
|
|
190
|
+
if (queryString) {
|
|
191
|
+
url = `${url}?${queryString}`;
|
|
192
|
+
}
|
|
193
|
+
return this.request(url);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Send a message to a playground session
|
|
197
|
+
*
|
|
198
|
+
* @param sessionId - The session UUID
|
|
199
|
+
* @param content - The message content
|
|
200
|
+
* @param inputs - Optional additional inputs for workflow nodes
|
|
201
|
+
* @returns The created message
|
|
202
|
+
*/
|
|
203
|
+
async sendMessage(sessionId, content, inputs) {
|
|
204
|
+
const config = this.getConfig();
|
|
205
|
+
const url = buildEndpointUrl(config, config.endpoints.playground.sendMessage, {
|
|
206
|
+
sessionId
|
|
207
|
+
});
|
|
208
|
+
const requestBody = { content };
|
|
209
|
+
if (inputs) {
|
|
210
|
+
requestBody.inputs = inputs;
|
|
211
|
+
}
|
|
212
|
+
const response = await this.request(url, {
|
|
213
|
+
method: 'POST',
|
|
214
|
+
body: JSON.stringify(requestBody)
|
|
215
|
+
});
|
|
216
|
+
if (!response.data) {
|
|
217
|
+
throw new Error('Failed to send message: No data returned');
|
|
218
|
+
}
|
|
219
|
+
return response.data;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Stop execution in a playground session
|
|
223
|
+
*
|
|
224
|
+
* @param sessionId - The session UUID
|
|
225
|
+
*/
|
|
226
|
+
async stopExecution(sessionId) {
|
|
227
|
+
const config = this.getConfig();
|
|
228
|
+
const url = buildEndpointUrl(config, config.endpoints.playground.stopExecution, {
|
|
229
|
+
sessionId
|
|
230
|
+
});
|
|
231
|
+
await this.request(url, {
|
|
232
|
+
method: 'POST'
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
// =========================================================================
|
|
236
|
+
// Polling
|
|
237
|
+
// =========================================================================
|
|
238
|
+
/**
|
|
239
|
+
* Start polling for new messages
|
|
240
|
+
*
|
|
241
|
+
* @param sessionId - The session UUID to poll
|
|
242
|
+
* @param callback - Callback function to handle new messages
|
|
243
|
+
* @param interval - Polling interval in milliseconds (default: 1500)
|
|
244
|
+
*/
|
|
245
|
+
startPolling(sessionId, callback, interval = DEFAULT_POLLING_INTERVAL) {
|
|
246
|
+
// Stop any existing polling
|
|
247
|
+
this.stopPolling();
|
|
248
|
+
this.pollingSessionId = sessionId;
|
|
249
|
+
this.currentBackoff = interval;
|
|
250
|
+
this.lastMessageTimestamp = null;
|
|
251
|
+
const poll = async () => {
|
|
252
|
+
if (this.pollingSessionId !== sessionId) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const response = await this.getMessages(sessionId, this.lastMessageTimestamp ?? undefined);
|
|
257
|
+
// Update last message timestamp
|
|
258
|
+
if (response.data && response.data.length > 0) {
|
|
259
|
+
const lastMessage = response.data[response.data.length - 1];
|
|
260
|
+
this.lastMessageTimestamp = lastMessage.timestamp;
|
|
261
|
+
}
|
|
262
|
+
// Reset backoff on successful request
|
|
263
|
+
this.currentBackoff = interval;
|
|
264
|
+
// Call the callback with new messages
|
|
265
|
+
callback(response);
|
|
266
|
+
// Stop polling if session is completed or failed
|
|
267
|
+
if (response.sessionStatus === 'completed' || response.sessionStatus === 'failed') {
|
|
268
|
+
this.stopPolling();
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
console.error('Polling error:', error);
|
|
274
|
+
// Exponential backoff on error
|
|
275
|
+
this.currentBackoff = Math.min(this.currentBackoff * 2, MAX_POLLING_BACKOFF);
|
|
276
|
+
}
|
|
277
|
+
// Schedule next poll
|
|
278
|
+
if (this.pollingSessionId === sessionId) {
|
|
279
|
+
this.pollingInterval = setTimeout(poll, this.currentBackoff);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
// Start polling immediately
|
|
283
|
+
poll();
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Stop polling for messages
|
|
287
|
+
*/
|
|
288
|
+
stopPolling() {
|
|
289
|
+
if (this.pollingInterval) {
|
|
290
|
+
clearTimeout(this.pollingInterval);
|
|
291
|
+
this.pollingInterval = null;
|
|
292
|
+
}
|
|
293
|
+
this.pollingSessionId = null;
|
|
294
|
+
this.lastMessageTimestamp = null;
|
|
295
|
+
this.currentBackoff = DEFAULT_POLLING_INTERVAL;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Check if polling is active
|
|
299
|
+
*
|
|
300
|
+
* @returns True if polling is active
|
|
301
|
+
*/
|
|
302
|
+
isPolling() {
|
|
303
|
+
return this.pollingSessionId !== null;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Get the current polling session ID
|
|
307
|
+
*
|
|
308
|
+
* @returns The session ID being polled, or null
|
|
309
|
+
*/
|
|
310
|
+
getPollingSessionId() {
|
|
311
|
+
return this.pollingSessionId;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Export singleton instance
|
|
316
|
+
*/
|
|
317
|
+
export const playgroundService = PlaygroundService.getInstance();
|