@runtypelabs/sdk 0.1.1

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.
Files changed (62) hide show
  1. package/README.md +398 -0
  2. package/dist/batch-builder.d.ts +106 -0
  3. package/dist/batch-builder.d.ts.map +1 -0
  4. package/dist/batch-builder.js +124 -0
  5. package/dist/batch-builder.js.map +1 -0
  6. package/dist/batches-namespace.d.ts +132 -0
  7. package/dist/batches-namespace.d.ts.map +1 -0
  8. package/dist/batches-namespace.js +128 -0
  9. package/dist/batches-namespace.js.map +1 -0
  10. package/dist/client.d.ts +121 -0
  11. package/dist/client.d.ts.map +1 -0
  12. package/dist/client.js +485 -0
  13. package/dist/client.js.map +1 -0
  14. package/dist/endpoints.d.ts +560 -0
  15. package/dist/endpoints.d.ts.map +1 -0
  16. package/dist/endpoints.js +725 -0
  17. package/dist/endpoints.js.map +1 -0
  18. package/dist/eval-builder.d.ts +216 -0
  19. package/dist/eval-builder.d.ts.map +1 -0
  20. package/dist/eval-builder.js +225 -0
  21. package/dist/eval-builder.js.map +1 -0
  22. package/dist/evals-namespace.d.ts +205 -0
  23. package/dist/evals-namespace.d.ts.map +1 -0
  24. package/dist/evals-namespace.js +208 -0
  25. package/dist/evals-namespace.js.map +1 -0
  26. package/dist/flow-builder.d.ts +620 -0
  27. package/dist/flow-builder.d.ts.map +1 -0
  28. package/dist/flow-builder.js +565 -0
  29. package/dist/flow-builder.js.map +1 -0
  30. package/dist/flow-result.d.ts +117 -0
  31. package/dist/flow-result.d.ts.map +1 -0
  32. package/dist/flow-result.js +175 -0
  33. package/dist/flow-result.js.map +1 -0
  34. package/dist/flows-namespace.d.ts +430 -0
  35. package/dist/flows-namespace.d.ts.map +1 -0
  36. package/dist/flows-namespace.js +679 -0
  37. package/dist/flows-namespace.js.map +1 -0
  38. package/dist/index.d.ts +23 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +76 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/prompts-namespace.d.ts +236 -0
  43. package/dist/prompts-namespace.d.ts.map +1 -0
  44. package/dist/prompts-namespace.js +222 -0
  45. package/dist/prompts-namespace.js.map +1 -0
  46. package/dist/runtype.d.ts +232 -0
  47. package/dist/runtype.d.ts.map +1 -0
  48. package/dist/runtype.js +367 -0
  49. package/dist/runtype.js.map +1 -0
  50. package/dist/stream-utils.d.ts +58 -0
  51. package/dist/stream-utils.d.ts.map +1 -0
  52. package/dist/stream-utils.js +348 -0
  53. package/dist/stream-utils.js.map +1 -0
  54. package/dist/transform.d.ts +21 -0
  55. package/dist/transform.d.ts.map +1 -0
  56. package/dist/transform.js +170 -0
  57. package/dist/transform.js.map +1 -0
  58. package/dist/types.d.ts +626 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +7 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +61 -0
@@ -0,0 +1,679 @@
1
+ "use strict";
2
+ /**
3
+ * FlowsNamespace - Static namespace for flow operations
4
+ *
5
+ * Provides factory methods for creating flow builders with different modes:
6
+ * - upsert: Create or update a flow by name
7
+ * - virtual: One-off execution without saving
8
+ * - use: Execute an existing flow by ID
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.RuntypeFlowBuilder = exports.FlowsNamespace = void 0;
45
+ const flow_result_1 = require("./flow-result");
46
+ // ============================================================================
47
+ // FlowsNamespace
48
+ // ============================================================================
49
+ class FlowsNamespace {
50
+ constructor(getClient) {
51
+ this.getClient = getClient;
52
+ }
53
+ /**
54
+ * Create or update a flow by name (upsert mode)
55
+ *
56
+ * The recommended pattern for code-first flow management.
57
+ * Creates the flow if it doesn't exist, updates if steps changed.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const result = await Runtype.flows.upsert({
62
+ * name: 'My Flow',
63
+ * createVersionOnChange: true
64
+ * })
65
+ * .prompt({ name: 'Analyze', model: 'gpt-4o', userPrompt: '...' })
66
+ * .stream()
67
+ * ```
68
+ */
69
+ upsert(config) {
70
+ return new RuntypeFlowBuilder(this.getClient, 'upsert', config);
71
+ }
72
+ /**
73
+ * Create a virtual flow (one-off, not saved)
74
+ *
75
+ * Use for temporary or ad-hoc flow execution.
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const result = await Runtype.flows.virtual({ name: 'Temp Flow' })
80
+ * .prompt({ name: 'Process', model: 'gpt-4o', userPrompt: '...' })
81
+ * .stream()
82
+ * ```
83
+ */
84
+ virtual(config) {
85
+ return new RuntypeFlowBuilder(this.getClient, 'virtual', config);
86
+ }
87
+ /**
88
+ * Use an existing flow by ID
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const result = await Runtype.flows.use('flow_123')
93
+ * .withRecord({ name: 'Test', type: 'data' })
94
+ * .stream()
95
+ * ```
96
+ */
97
+ use(flowId) {
98
+ return new RuntypeFlowBuilder(this.getClient, 'existing', undefined, flowId);
99
+ }
100
+ /**
101
+ * Quick execution of an existing flow
102
+ *
103
+ * @example
104
+ * ```typescript
105
+ * const result = await Runtype.flows.execute('flow_123', {
106
+ * record: { name: 'Test', type: 'data' },
107
+ * streamResponse: true
108
+ * })
109
+ * ```
110
+ */
111
+ async execute(flowId, options) {
112
+ const builder = this.use(flowId);
113
+ if (options?.record)
114
+ builder.withRecord(options.record);
115
+ if (options?.messages)
116
+ builder.withMessages(options.messages);
117
+ return options?.streamResponse !== false ? builder.stream() : builder.result();
118
+ }
119
+ }
120
+ exports.FlowsNamespace = FlowsNamespace;
121
+ // ============================================================================
122
+ // RuntypeFlowBuilder
123
+ // ============================================================================
124
+ /**
125
+ * Fluent builder for constructing and executing flows
126
+ */
127
+ class RuntypeFlowBuilder {
128
+ constructor(getClient, mode, config, flowId) {
129
+ this.getClient = getClient;
130
+ this.steps = [];
131
+ this.stepCounter = 0;
132
+ this.upsertOptions = {};
133
+ this.dispatchOptions = {};
134
+ this.mode = mode;
135
+ if (mode === 'existing' && flowId) {
136
+ this.existingFlowId = flowId;
137
+ this.flowConfig = { name: '' };
138
+ }
139
+ else if (config) {
140
+ const { createVersionOnChange, allowOverwriteExternalChanges, ...flowConfig } = config;
141
+ this.flowConfig = flowConfig;
142
+ if (mode === 'upsert') {
143
+ this.upsertOptions = {
144
+ createVersionOnChange: createVersionOnChange ?? true,
145
+ ...(allowOverwriteExternalChanges !== undefined && { allowOverwriteExternalChanges }),
146
+ };
147
+ }
148
+ }
149
+ else {
150
+ this.flowConfig = { name: 'Untitled Flow' };
151
+ }
152
+ }
153
+ // ============================================================================
154
+ // Configuration Methods
155
+ // ============================================================================
156
+ /**
157
+ * Set the record configuration
158
+ */
159
+ withRecord(config) {
160
+ this.recordConfig = config;
161
+ return this;
162
+ }
163
+ /**
164
+ * Set conversation messages
165
+ */
166
+ withMessages(messages) {
167
+ this.messagesConfig = messages;
168
+ return this;
169
+ }
170
+ /**
171
+ * Set dispatch options
172
+ */
173
+ withOptions(options) {
174
+ this.dispatchOptions = { ...this.dispatchOptions, ...options };
175
+ return this;
176
+ }
177
+ // ============================================================================
178
+ // Step Methods
179
+ // ============================================================================
180
+ /**
181
+ * Add a prompt step
182
+ */
183
+ prompt(config) {
184
+ this.addStep('prompt', config.name, {
185
+ model: config.model,
186
+ userPrompt: config.userPrompt,
187
+ text: config.userPrompt,
188
+ systemPrompt: config.systemPrompt,
189
+ previousMessages: config.previousMessages,
190
+ outputVariable: config.outputVariable,
191
+ responseFormat: config.responseFormat,
192
+ temperature: config.temperature,
193
+ maxTokens: config.maxTokens,
194
+ reasoning: config.reasoning,
195
+ streamOutput: config.streamOutput,
196
+ tools: config.tools,
197
+ }, config.enabled);
198
+ return this;
199
+ }
200
+ /**
201
+ * Add a fetch URL step
202
+ */
203
+ fetchUrl(config) {
204
+ this.addStep('fetch-url', config.name, {
205
+ http: {
206
+ url: config.url,
207
+ method: config.method || 'GET',
208
+ headers: config.headers,
209
+ body: config.body,
210
+ },
211
+ fetchMethod: config.fetchMethod,
212
+ firecrawl: config.firecrawl,
213
+ outputVariable: config.outputVariable,
214
+ errorHandling: config.errorHandling,
215
+ streamOutput: config.streamOutput,
216
+ }, config.enabled);
217
+ return this;
218
+ }
219
+ /**
220
+ * Add a transform data step
221
+ */
222
+ transformData(config) {
223
+ this.addStep('transform-data', config.name, {
224
+ script: config.script,
225
+ outputVariable: config.outputVariable,
226
+ streamOutput: config.streamOutput,
227
+ }, config.enabled);
228
+ return this;
229
+ }
230
+ /**
231
+ * Add a set variable step
232
+ */
233
+ setVariable(config) {
234
+ this.addStep('set-variable', config.name, {
235
+ variableName: config.variableName,
236
+ value: config.value,
237
+ }, config.enabled);
238
+ return this;
239
+ }
240
+ /**
241
+ * Add a conditional step
242
+ */
243
+ conditional(config) {
244
+ this.addStep('conditional', config.name, {
245
+ condition: config.condition,
246
+ trueSteps: config.trueSteps || [],
247
+ falseSteps: config.falseSteps || [],
248
+ }, config.enabled);
249
+ return this;
250
+ }
251
+ /**
252
+ * Add a search step
253
+ */
254
+ search(config) {
255
+ this.addStep('search', config.name, {
256
+ provider: config.provider,
257
+ query: config.query,
258
+ maxResults: config.maxResults,
259
+ outputVariable: config.outputVariable,
260
+ returnCitations: config.returnCitations,
261
+ errorHandling: config.errorHandling,
262
+ streamOutput: config.streamOutput,
263
+ }, config.enabled);
264
+ return this;
265
+ }
266
+ /**
267
+ * Add a send email step
268
+ */
269
+ sendEmail(config) {
270
+ this.addStep('send-email', config.name, {
271
+ to: config.to,
272
+ from: config.from || 'no-reply@messages.runtype.com',
273
+ subject: config.subject,
274
+ html: config.html,
275
+ outputVariable: config.outputVariable,
276
+ errorHandling: config.errorHandling,
277
+ streamOutput: config.streamOutput,
278
+ }, config.enabled);
279
+ return this;
280
+ }
281
+ /**
282
+ * Add a send stream step
283
+ */
284
+ sendStream(config) {
285
+ this.addStep('send-stream', config.name, {
286
+ message: config.message,
287
+ }, config.enabled);
288
+ return this;
289
+ }
290
+ /**
291
+ * Add a retrieve record step
292
+ */
293
+ retrieveRecord(config) {
294
+ this.addStep('retrieve-record', config.name, {
295
+ recordType: config.recordType,
296
+ recordName: config.recordName,
297
+ fieldsToInclude: config.fieldsToInclude,
298
+ fieldsToExclude: config.fieldsToExclude,
299
+ outputVariable: config.outputVariable,
300
+ streamOutput: config.streamOutput,
301
+ }, config.enabled);
302
+ return this;
303
+ }
304
+ /**
305
+ * Add an upsert record step
306
+ */
307
+ upsertRecord(config) {
308
+ this.addStep('upsert-record', config.name, {
309
+ recordType: config.recordType,
310
+ recordName: config.recordName,
311
+ sourceVariable: config.sourceVariable,
312
+ mergeStrategy: config.mergeStrategy,
313
+ outputVariable: config.outputVariable,
314
+ errorHandling: config.errorHandling,
315
+ streamOutput: config.streamOutput,
316
+ }, config.enabled);
317
+ return this;
318
+ }
319
+ /**
320
+ * Add a vector search step
321
+ */
322
+ vectorSearch(config) {
323
+ this.addStep('vector-search', config.name, {
324
+ query: config.query,
325
+ recordType: config.recordType,
326
+ embeddingModel: config.embeddingModel,
327
+ limit: config.limit,
328
+ threshold: config.threshold,
329
+ outputVariable: config.outputVariable,
330
+ includeDistance: config.includeDistance,
331
+ streamOutput: config.streamOutput,
332
+ }, config.enabled);
333
+ return this;
334
+ }
335
+ /**
336
+ * Add a generate embedding step
337
+ */
338
+ generateEmbedding(config) {
339
+ this.addStep('generate-embedding', config.name, {
340
+ inputSource: 'text',
341
+ text: config.text,
342
+ embeddingModel: config.embeddingModel,
343
+ maxLength: config.maxLength,
344
+ outputVariable: config.outputVariable,
345
+ streamOutput: config.streamOutput,
346
+ }, config.enabled);
347
+ return this;
348
+ }
349
+ /**
350
+ * Add a wait until step
351
+ */
352
+ waitUntil(config) {
353
+ this.addStep('wait-until', config.name, {
354
+ delayMs: config.delayMs,
355
+ continueOnTimeout: config.continueOnTimeout,
356
+ poll: config.poll,
357
+ outputVariable: config.outputVariable,
358
+ errorHandling: config.errorHandling,
359
+ streamOutput: config.streamOutput,
360
+ }, config.enabled);
361
+ return this;
362
+ }
363
+ /**
364
+ * Add a send event step
365
+ */
366
+ sendEvent(config) {
367
+ this.addStep('send-event', config.name, {
368
+ provider: config.provider,
369
+ eventName: config.eventName,
370
+ properties: config.properties,
371
+ outputVariable: config.outputVariable,
372
+ errorHandling: config.errorHandling,
373
+ streamOutput: config.streamOutput,
374
+ }, config.enabled);
375
+ return this;
376
+ }
377
+ /**
378
+ * Add a send text step
379
+ */
380
+ sendText(config) {
381
+ this.addStep('send-text', config.name, {
382
+ to: config.to,
383
+ from: config.from,
384
+ message: config.message,
385
+ outputVariable: config.outputVariable,
386
+ errorHandling: config.errorHandling,
387
+ streamOutput: config.streamOutput,
388
+ }, config.enabled);
389
+ return this;
390
+ }
391
+ /**
392
+ * Add a fetch GitHub step
393
+ */
394
+ fetchGitHub(config) {
395
+ this.addStep('fetch-github', config.name, {
396
+ repository: config.repository,
397
+ branch: config.branch,
398
+ path: config.path,
399
+ outputVariable: config.outputVariable,
400
+ streamOutput: config.streamOutput,
401
+ }, config.enabled);
402
+ return this;
403
+ }
404
+ async stream(arg1, arg2) {
405
+ const config = this.build();
406
+ let callbacks;
407
+ let localTools;
408
+ if (arg1) {
409
+ if ('localTools' in arg1) {
410
+ localTools = arg1.localTools;
411
+ }
412
+ else {
413
+ callbacks = arg1;
414
+ if (arg2) {
415
+ localTools = arg2.localTools;
416
+ }
417
+ }
418
+ }
419
+ // Handle local tools if provided
420
+ if (localTools) {
421
+ return this.runWithLocalTools(localTools, callbacks);
422
+ }
423
+ config.options = { ...config.options, streamResponse: true };
424
+ const client = this.getClient();
425
+ const response = await client.dispatch(config);
426
+ const result = new flow_result_1.FlowResult(response);
427
+ // If callbacks provided, process immediately
428
+ if (callbacks) {
429
+ await result.stream(callbacks);
430
+ }
431
+ return result;
432
+ }
433
+ /**
434
+ * Execute the flow and wait for complete result (no streaming)
435
+ *
436
+ * Returns a FlowResult after all steps have completed.
437
+ *
438
+ * @example
439
+ * ```typescript
440
+ * const result = await Runtype.flows.use('flow_123')
441
+ * .withRecord({ ... })
442
+ * .result()
443
+ *
444
+ * const analysis = await result.getResult('Analyze')
445
+ * const allResults = await result.getAllResults()
446
+ * ```
447
+ */
448
+ async result(options) {
449
+ const config = this.build();
450
+ // Handle local tools if provided
451
+ if (options?.localTools) {
452
+ return this.runWithLocalTools(options.localTools);
453
+ }
454
+ config.options = { ...config.options, streamResponse: true };
455
+ const client = this.getClient();
456
+ const response = await client.dispatch(config);
457
+ const result = new flow_result_1.FlowResult(response);
458
+ // Pre-process the stream to cache results
459
+ await result.getSummary();
460
+ return result;
461
+ }
462
+ /**
463
+ * Execute the flow with local tools (automatic pause/resume loop)
464
+ *
465
+ * @param localTools - Map of tool names to async functions that execute the tool logic
466
+ * @returns The final result of the flow execution
467
+ */
468
+ async runWithLocalTools(localTools, callbacks) {
469
+ const config = this.build();
470
+ const isStreaming = !!callbacks;
471
+ // Force options
472
+ config.options = {
473
+ ...config.options,
474
+ streamResponse: isStreaming,
475
+ };
476
+ // Add stream_response snake_case too just in case
477
+ if (config.options) {
478
+ config.options.stream_response = isStreaming;
479
+ }
480
+ const client = this.getClient();
481
+ // Accumulated results across pause/resume cycles - moved outside processStep
482
+ // so results persist when flow pauses and resumes
483
+ const accumulatedSummary = {
484
+ results: new Map(),
485
+ success: true
486
+ };
487
+ // Helper to process a step result (either from stream or JSON)
488
+ const processStep = async (response) => {
489
+ if (isStreaming) {
490
+ // Stream processing
491
+ let pausedState = null;
492
+ // Wrap user callbacks to intercept paused event
493
+ const wrappedCallbacks = {
494
+ ...callbacks,
495
+ onFlowStart: (event) => callbacks?.onFlowStart?.(event),
496
+ onStepStart: (event) => callbacks?.onStepStart?.(event),
497
+ onStepChunk: (chunk, event) => callbacks?.onStepChunk?.(chunk, event),
498
+ onStepComplete: (result, event) => callbacks?.onStepComplete?.(result, event),
499
+ onFlowComplete: (event) => callbacks?.onFlowComplete?.(event),
500
+ onError: (error) => callbacks?.onError?.(error)
501
+ };
502
+ // Use streamEvents from stream-utils
503
+ const { streamEvents } = await Promise.resolve().then(() => __importStar(require('./stream-utils')));
504
+ try {
505
+ for await (const event of streamEvents(response)) {
506
+ // Check for flow_paused
507
+ if (event.type === 'flow_paused') {
508
+ pausedState = {
509
+ toolName: event.toolName,
510
+ parameters: event.parameters,
511
+ executionId: event.executionId
512
+ };
513
+ }
514
+ if (event.type === 'step_waiting_local') {
515
+ pausedState = {
516
+ toolName: event.toolName,
517
+ parameters: event.parameters,
518
+ executionId: event.executionId
519
+ };
520
+ }
521
+ // Handle standard events via callbacks
522
+ switch (event.type) {
523
+ case 'flow_start':
524
+ wrappedCallbacks.onFlowStart?.(event);
525
+ break;
526
+ case 'step_start':
527
+ wrappedCallbacks.onStepStart?.(event);
528
+ break;
529
+ case 'step_chunk': {
530
+ // Normalize API's 'text' field to 'chunk' for consistency
531
+ const chunkText = event.chunk || event.text || '';
532
+ wrappedCallbacks.onStepChunk?.(chunkText, event);
533
+ break;
534
+ }
535
+ case 'step_complete':
536
+ // Accumulate results in the outer summary that persists across pause/resume
537
+ accumulatedSummary.results?.set(event.name, event.result);
538
+ wrappedCallbacks.onStepComplete?.(event.result, event);
539
+ break;
540
+ case 'flow_complete':
541
+ wrappedCallbacks.onFlowComplete?.(event);
542
+ break;
543
+ case 'flow_error':
544
+ wrappedCallbacks.onError?.(new Error(event.error));
545
+ break;
546
+ }
547
+ }
548
+ }
549
+ catch (e) {
550
+ wrappedCallbacks.onError?.(e instanceof Error ? e : new Error(String(e)));
551
+ throw e;
552
+ }
553
+ if (pausedState) {
554
+ return { done: false, result: { status: 'paused', pausedReason: { type: 'local_action', ...pausedState } } };
555
+ }
556
+ return { done: true, result: accumulatedSummary };
557
+ }
558
+ else {
559
+ // Non-streaming (JSON)
560
+ const data = await response.json();
561
+ return {
562
+ done: data.status !== 'paused',
563
+ result: data
564
+ };
565
+ }
566
+ };
567
+ // Initial dispatch
568
+ let currentResponse;
569
+ if (isStreaming) {
570
+ currentResponse = await client.dispatch(config);
571
+ }
572
+ else {
573
+ const data = await client.post('/dispatch', config);
574
+ currentResponse = new Response(JSON.stringify(data), { headers: { 'content-type': 'application/json' } });
575
+ }
576
+ // Loop
577
+ while (true) {
578
+ const { done, result } = await processStep(currentResponse);
579
+ if (done) {
580
+ if (isStreaming) {
581
+ // Create FlowResult with summary
582
+ const finalResponse = new Response(JSON.stringify(result), { headers: { 'content-type': 'application/json' } });
583
+ return new flow_result_1.FlowResult(finalResponse, result);
584
+ }
585
+ return new flow_result_1.FlowResult(new Response(JSON.stringify(result), { headers: { 'content-type': 'application/json' } }));
586
+ }
587
+ // Handle Pause
588
+ if (result.status === 'paused' && result.pausedReason?.type === 'local_action') {
589
+ const { toolName, parameters, executionId } = result.pausedReason;
590
+ if (!localTools[toolName]) {
591
+ throw new Error(`Local tool "${toolName}" required but not provided in localTools map`);
592
+ }
593
+ try {
594
+ // Execute local tool logic
595
+ const toolResult = await localTools[toolName](parameters);
596
+ // Resume flow execution - API expects snake_case field names
597
+ const resumeData = {
598
+ execution_id: executionId,
599
+ tool_outputs: { [toolName]: toolResult },
600
+ stream_response: isStreaming
601
+ };
602
+ if (isStreaming) {
603
+ currentResponse = await client.requestStream('/dispatch/resume', {
604
+ method: 'POST',
605
+ body: JSON.stringify(resumeData)
606
+ });
607
+ }
608
+ else {
609
+ const data = await client.post('/dispatch/resume', resumeData);
610
+ currentResponse = new Response(JSON.stringify(data), { headers: { 'content-type': 'application/json' } });
611
+ }
612
+ }
613
+ catch (error) {
614
+ throw new Error(`Error executing local tool "${toolName}": ${error instanceof Error ? error.message : String(error)}`);
615
+ }
616
+ }
617
+ else {
618
+ break;
619
+ }
620
+ }
621
+ throw new Error('Unexpected end of flow execution loop');
622
+ }
623
+ build() {
624
+ const flowMode = this.mode === 'existing' ? 'existing' : this.mode;
625
+ const flow = this.existingFlowId
626
+ ? { id: this.existingFlowId }
627
+ : { name: this.flowConfig.name, steps: this.steps };
628
+ const request = { flow };
629
+ if (this.recordConfig) {
630
+ request.record = this.recordConfig;
631
+ }
632
+ if (this.messagesConfig) {
633
+ request.messages = this.messagesConfig;
634
+ }
635
+ const options = {
636
+ flowMode,
637
+ ...this.dispatchOptions,
638
+ };
639
+ // Auto-detect recordMode based on record config if not explicitly set
640
+ if (this.recordConfig && !this.dispatchOptions.recordMode) {
641
+ if (this.recordConfig.id) {
642
+ options.recordMode = 'existing';
643
+ }
644
+ else if (this.recordConfig.name || this.recordConfig.type) {
645
+ options.recordMode = 'create';
646
+ }
647
+ else {
648
+ options.recordMode = 'virtual';
649
+ }
650
+ }
651
+ if (this.mode === 'upsert' && Object.keys(this.upsertOptions).length > 0) {
652
+ options.upsertOptions = this.upsertOptions;
653
+ }
654
+ request.options = options;
655
+ return request;
656
+ }
657
+ // ============================================================================
658
+ // Private Helpers
659
+ // ============================================================================
660
+ addStep(type, name, config, enabled = true) {
661
+ this.stepCounter++;
662
+ const cleanConfig = {};
663
+ for (const [key, value] of Object.entries(config)) {
664
+ if (value !== undefined) {
665
+ cleanConfig[key] = value;
666
+ }
667
+ }
668
+ this.steps.push({
669
+ id: `step-${this.stepCounter}`,
670
+ type,
671
+ name,
672
+ order: this.stepCounter,
673
+ enabled,
674
+ config: cleanConfig,
675
+ });
676
+ }
677
+ }
678
+ exports.RuntypeFlowBuilder = RuntypeFlowBuilder;
679
+ //# sourceMappingURL=flows-namespace.js.map