orchestrator-client 5.7.3 → 5.7.10

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/index.cjs CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ DEFAULT_FLOW_TIMEOUT_MS: () => DEFAULT_FLOW_TIMEOUT_MS,
33
34
  EVENT_ERROR_EVENT_RECORDED: () => EVENT_ERROR_EVENT_RECORDED,
34
35
  EVENT_MESSAGE_ADDED: () => EVENT_MESSAGE_ADDED,
35
36
  EVENT_MESSAGE_STREAMING: () => EVENT_MESSAGE_STREAMING,
@@ -41,6 +42,10 @@ __export(index_exports, {
41
42
  EVENT_TASK_ITERATION_CHANGED: () => EVENT_TASK_ITERATION_CHANGED,
42
43
  EVENT_TASK_RESULT_UPDATED: () => EVENT_TASK_RESULT_UPDATED,
43
44
  EVENT_TASK_STATUS_CHANGED: () => EVENT_TASK_STATUS_CHANGED,
45
+ Flow: () => Flow,
46
+ FlowCancelledError: () => FlowCancelledError,
47
+ FlowError: () => FlowError,
48
+ FlowTimeoutError: () => FlowTimeoutError,
44
49
  Orchestrator: () => Orchestrator,
45
50
  OrchestratorAPIError: () => OrchestratorAPIError,
46
51
  OrchestratorAsync: () => OrchestratorAsync,
@@ -51,8 +56,13 @@ __export(index_exports, {
51
56
  OrchestratorNotFoundError: () => OrchestratorNotFoundError,
52
57
  RealtimeClient: () => RealtimeClient,
53
58
  VERSION: () => VERSION,
59
+ camelToSnake: () => camelToSnake,
54
60
  createInsecureFetch: () => createInsecureFetch,
55
- loadConfig: () => loadConfig
61
+ deepCamelCase: () => deepCamelCase,
62
+ extractJsonFromMessage: () => extractJsonFromMessage,
63
+ loadConfig: () => loadConfig,
64
+ setupDefaultClient: () => setupDefaultClient,
65
+ snakeToCamel: () => snakeToCamel
56
66
  });
57
67
  module.exports = __toCommonJS(index_exports);
58
68
 
@@ -73,8 +83,8 @@ var OrchestratorConnectionError = class extends OrchestratorError {
73
83
  }
74
84
  };
75
85
  var OrchestratorAuthError = class extends OrchestratorError {
76
- constructor(message, statusCode = 401) {
77
- super(message, { statusCode });
86
+ constructor(message, statusCode = 401, errorCode) {
87
+ super(message, { statusCode, errorCode });
78
88
  this.name = "OrchestratorAuthError";
79
89
  }
80
90
  };
@@ -101,6 +111,28 @@ var OrchestratorConfigError = class extends OrchestratorError {
101
111
  }
102
112
  };
103
113
 
114
+ // src/utils.ts
115
+ function snakeToCamel(str) {
116
+ return str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
117
+ }
118
+ function camelToSnake(str) {
119
+ return str.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
120
+ }
121
+ function deepCamelCase(obj) {
122
+ if (Array.isArray(obj)) {
123
+ return obj.map(deepCamelCase);
124
+ }
125
+ if (typeof obj === "object" && obj !== null) {
126
+ return Object.fromEntries(
127
+ Object.entries(obj).map(([key, value]) => [
128
+ snakeToCamel(key),
129
+ deepCamelCase(value)
130
+ ])
131
+ );
132
+ }
133
+ return obj;
134
+ }
135
+
104
136
  // src/client.ts
105
137
  var RETRY_BACKOFF_BASE = 500;
106
138
  var DEFAULT_TIMEOUT_MS = 3e4;
@@ -120,22 +152,66 @@ function buildTaskSummary(t) {
120
152
  return {
121
153
  id: t.id ?? "",
122
154
  status: t.status ?? "",
123
- workflowId: t.workflowId ?? t.workflow_id ?? "",
155
+ workflowId: t.workflowId ?? "",
124
156
  iteration: t.iteration ?? 0,
125
- maxIterations: t.maxIterations ?? t.max_iterations ?? 0,
126
- goalPrompt: t.goalPrompt ?? t.goal_prompt ?? "",
157
+ maxIterations: t.maxIterations ?? 0,
158
+ goalPrompt: t.goalPrompt ?? "",
127
159
  result: t.result ?? "",
128
- resultLocalized: t.resultLocalized ?? t.result_localized ?? null,
129
- approvalReason: t.approvalReason ?? t.approval_reason ?? "",
130
- ticketId: t.ticketId ?? t.ticket_id ?? null,
131
- availableTools: t.availableTools ?? t.available_tools ?? null,
160
+ resultLocalized: t.resultLocalized ?? null,
161
+ approvalReason: t.approvalReason ?? "",
162
+ ticketId: t.ticketId ?? null,
163
+ availableTools: t.availableTools ?? null,
132
164
  insight: t.insight ?? null,
133
- insightLocalized: t.insightLocalized ?? t.insight_localized ?? null,
134
- createdAt: t.createdAt ?? t.created_at ?? "",
135
- updatedAt: t.updatedAt ?? t.updated_at ?? "",
136
- pendingTranslationsForLocales: t.pendingTranslationsForLocales ?? t.pending_translations_for_locales ?? null
165
+ insightLocalized: t.insightLocalized ?? null,
166
+ createdAt: t.createdAt ?? "",
167
+ updatedAt: t.updatedAt ?? "",
168
+ pendingTranslationsForLocales: t.pendingTranslationsForLocales ?? null
137
169
  };
138
170
  }
171
+ function parseApiErrorBody(body, fallbackMessage) {
172
+ let errorCode = body.error_code ?? null;
173
+ if (!errorCode && body.error && typeof body.error === "object") {
174
+ const nested = body.error;
175
+ errorCode = nested.code ?? null;
176
+ }
177
+ let message = null;
178
+ if (typeof body.error === "string") {
179
+ message = body.error;
180
+ } else if (typeof body.message === "string") {
181
+ message = body.message;
182
+ }
183
+ let details = body.details ?? null;
184
+ const detail = body.detail;
185
+ if (typeof detail === "string") {
186
+ message = detail;
187
+ } else if (detail && typeof detail === "object" && !Array.isArray(detail)) {
188
+ const detailObj = detail;
189
+ if (!errorCode) {
190
+ errorCode = detailObj.error_code ?? null;
191
+ }
192
+ if (typeof detailObj.error === "string") {
193
+ message = detailObj.error;
194
+ } else if (typeof detailObj.message === "string") {
195
+ message = detailObj.message;
196
+ }
197
+ if (!details) {
198
+ details = detailObj;
199
+ }
200
+ }
201
+ if (!message) {
202
+ message = fallbackMessage;
203
+ }
204
+ const missingFields = body.missing_fields;
205
+ if (Array.isArray(missingFields) && missingFields.length > 0) {
206
+ const fields = missingFields.filter(
207
+ (f) => typeof f === "string"
208
+ );
209
+ if (fields.length > 0) {
210
+ message = `${message} (missing: ${fields.join(", ")})`;
211
+ }
212
+ }
213
+ return { message, errorCode, details };
214
+ }
139
215
  var OrchestratorAsync = class {
140
216
  constructor(opts = {}) {
141
217
  this._abortController = null;
@@ -149,7 +225,7 @@ var OrchestratorAsync = class {
149
225
  this._timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
150
226
  this._maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
151
227
  this._locale = opts.locale;
152
- this._fetch = opts.fetch ?? globalThis.fetch;
228
+ this._fetch = opts.fetch ?? globalThis.fetch.bind(globalThis);
153
229
  if (opts.insecure && !opts.fetch && typeof process !== "undefined" && process.versions?.node) {
154
230
  this._insecure = true;
155
231
  }
@@ -163,6 +239,11 @@ var OrchestratorAsync = class {
163
239
  _makeUrl(path) {
164
240
  return `${this._baseUrl}${path}`;
165
241
  }
242
+ _makeAbsoluteUrl(path) {
243
+ const raw = this._makeUrl(path);
244
+ const base = typeof globalThis.location !== "undefined" ? globalThis.location.href : void 0;
245
+ return new URL(raw, base);
246
+ }
166
247
  async _resolveHeaders() {
167
248
  const headers = {};
168
249
  if (this._apiKey) {
@@ -179,7 +260,7 @@ var OrchestratorAsync = class {
179
260
  return headers;
180
261
  }
181
262
  async _request(method, path, opts) {
182
- const url = new URL(this._makeUrl(path));
263
+ const url = this._makeAbsoluteUrl(path);
183
264
  if (opts?.params) {
184
265
  for (const [key, value] of Object.entries(opts.params)) {
185
266
  if (value !== void 0) {
@@ -207,16 +288,21 @@ var OrchestratorAsync = class {
207
288
  signal
208
289
  });
209
290
  clearTimeout(timeoutId);
210
- if (response.status === 401) {
211
- throw new OrchestratorAuthError(
212
- `Authentication failed for ${method} ${path}`,
213
- 401
214
- );
215
- }
216
- if (response.status === 403) {
291
+ if (response.status === 401 || response.status === 403) {
292
+ const defaultAuthMsg = response.status === 401 ? `Authentication failed for ${method} ${path}` : `Access denied for ${method} ${path}`;
293
+ let authErrorCode = null;
294
+ let authErrorMsg = defaultAuthMsg;
295
+ try {
296
+ const body = await response.clone().json();
297
+ const parsed = parseApiErrorBody(body, defaultAuthMsg);
298
+ authErrorMsg = parsed.message;
299
+ authErrorCode = parsed.errorCode;
300
+ } catch {
301
+ }
217
302
  throw new OrchestratorAuthError(
218
- `Access denied for ${method} ${path}`,
219
- 403
303
+ authErrorMsg,
304
+ response.status,
305
+ authErrorCode
220
306
  );
221
307
  }
222
308
  if (response.status === 404) {
@@ -243,21 +329,27 @@ var OrchestratorAsync = class {
243
329
  if (response.ok) {
244
330
  const contentType = response.headers.get("content-type") ?? "";
245
331
  if (contentType.includes("application/json")) {
246
- return response.json();
332
+ return deepCamelCase(await response.json());
247
333
  }
248
334
  return { _text: await response.text() };
249
335
  }
250
- let errorMessage;
336
+ const defaultMessage = `API Error with status ${response.status}`;
337
+ let errorMessage = defaultMessage;
251
338
  let errorCode = null;
252
339
  let errorDetails = null;
253
340
  try {
254
- const body = await response.json();
255
- const error = body.error ?? body;
256
- errorCode = error.code ?? null;
257
- errorMessage = error.message ?? await response.text();
258
- errorDetails = error.details ?? null;
341
+ const clonedResponse = response.clone();
342
+ const body = await clonedResponse.json();
343
+ const parsed = parseApiErrorBody(body, JSON.stringify(body));
344
+ errorMessage = parsed.message;
345
+ errorCode = parsed.errorCode;
346
+ errorDetails = parsed.details;
259
347
  } catch {
260
- errorMessage = await response.text();
348
+ try {
349
+ errorMessage = await response.text();
350
+ } catch {
351
+ errorMessage = defaultMessage;
352
+ }
261
353
  }
262
354
  throw new OrchestratorAPIError(
263
355
  errorMessage,
@@ -327,7 +419,7 @@ var OrchestratorAsync = class {
327
419
  params: {
328
420
  page: params?.page,
329
421
  limit: params?.limit,
330
- order_by: params?.orderBy,
422
+ order_by: params?.orderBy ? camelToSnake(params.orderBy) : void 0,
331
423
  order_direction: params?.orderDirection,
332
424
  workflow_id: params?.workflowId
333
425
  },
@@ -400,10 +492,10 @@ var OrchestratorAsync = class {
400
492
  };
401
493
  }
402
494
  async getArchivedMessageContent(taskId, messageId) {
403
- return this._get(
404
- "/task/message/archived-content",
405
- { task_id: taskId, message_id: messageId }
406
- );
495
+ return this._get("/task/message/archived-content", {
496
+ task_id: taskId,
497
+ message_id: messageId
498
+ });
407
499
  }
408
500
  async getTaskCompactions(taskId) {
409
501
  return this._get("/task/compactions", {
@@ -462,19 +554,39 @@ var OrchestratorAsync = class {
462
554
  // ------------------------------------------------------------------
463
555
  // Attachments
464
556
  // ------------------------------------------------------------------
465
- async uploadAttachment(file, filename) {
557
+ async uploadAttachment(file, filename, options) {
466
558
  const formData = new FormData();
467
559
  formData.append("file", file, filename);
468
560
  const headers = await this._resolveHeaders();
469
561
  const response = await this._fetch(this._makeUrl("/attachment"), {
470
562
  method: "POST",
471
563
  headers: { ...headers },
472
- body: formData
564
+ body: formData,
565
+ signal: options?.signal
473
566
  });
474
567
  if (!response.ok) {
568
+ const defaultMessage = `Attachment upload failed: ${response.statusText}`;
569
+ let errorMessage = defaultMessage;
570
+ let errorCode = null;
571
+ let errorDetails = null;
572
+ try {
573
+ const body = await response.clone().json();
574
+ const parsed = parseApiErrorBody(body, defaultMessage);
575
+ errorMessage = parsed.message;
576
+ errorCode = parsed.errorCode;
577
+ errorDetails = parsed.details;
578
+ } catch {
579
+ try {
580
+ errorMessage = await response.text() || defaultMessage;
581
+ } catch {
582
+ errorMessage = defaultMessage;
583
+ }
584
+ }
475
585
  throw new OrchestratorAPIError(
476
- `Attachment upload failed: ${response.statusText}`,
477
- response.status
586
+ errorMessage,
587
+ response.status,
588
+ errorCode,
589
+ errorDetails ?? void 0
478
590
  );
479
591
  }
480
592
  const data = await response.json();
@@ -942,7 +1054,7 @@ var OrchestratorAsync = class {
942
1054
  // ------------------------------------------------------------------
943
1055
  async listErrors(params) {
944
1056
  const authHeaders = await this._resolveHeaders();
945
- const url = new URL(this._makeUrl("/errors"));
1057
+ const url = this._makeAbsoluteUrl("/errors");
946
1058
  if (params?.page !== void 0)
947
1059
  url.searchParams.set("page", String(params.page));
948
1060
  if (params?.limit !== void 0)
@@ -992,10 +1104,24 @@ var OrchestratorAsync = class {
992
1104
  if (since) params.since = since;
993
1105
  return this._get("/errors/stats", params);
994
1106
  }
995
- async countErrors(since) {
996
- const params = {};
997
- if (since) params.since = since;
998
- return this._get("/errors/count", params);
1107
+ async countErrors(since, severity) {
1108
+ const authHeaders = await this._resolveHeaders();
1109
+ const url = new URL(this._makeUrl("/errors/count"));
1110
+ if (since) url.searchParams.set("since", since);
1111
+ for (const s of severity ?? []) {
1112
+ url.searchParams.append("severity", s);
1113
+ }
1114
+ const response = await this._fetch(url.toString(), {
1115
+ method: "GET",
1116
+ headers: { ...authHeaders }
1117
+ });
1118
+ if (!response.ok) {
1119
+ throw new OrchestratorAPIError(
1120
+ `countErrors failed: ${response.statusText}`,
1121
+ response.status
1122
+ );
1123
+ }
1124
+ return deepCamelCase(await response.json());
999
1125
  }
1000
1126
  async purgeErrors() {
1001
1127
  return this._delete("/errors");
@@ -1027,7 +1153,35 @@ var OrchestratorAsync = class {
1027
1153
  return this._get("/configuration/system/status");
1028
1154
  }
1029
1155
  async updateSettings(settings) {
1030
- return this._post("/configuration/system/settings", settings);
1156
+ const body = {};
1157
+ if (settings.agentModelId !== void 0) {
1158
+ body.agent_model_id = settings.agentModelId;
1159
+ }
1160
+ if (settings.orchestratorModelId !== void 0) {
1161
+ body.orchestrator_model_id = settings.orchestratorModelId;
1162
+ }
1163
+ if (settings.compactorModelId !== void 0) {
1164
+ body.compactor_model_id = settings.compactorModelId;
1165
+ }
1166
+ if (settings.journalModelId !== void 0) {
1167
+ body.journal_model_id = settings.journalModelId;
1168
+ }
1169
+ if (settings.summaryModelId !== void 0) {
1170
+ body.summary_model_id = settings.summaryModelId;
1171
+ }
1172
+ if (settings.translateModelId !== void 0) {
1173
+ body.translate_model_id = settings.translateModelId;
1174
+ }
1175
+ if (settings.maxConcurrentTasksPerReplica !== void 0) {
1176
+ body.max_concurrent_tasks_per_replica = settings.maxConcurrentTasksPerReplica;
1177
+ }
1178
+ if (settings.subagentsEnabled !== void 0) {
1179
+ body.subagents_enabled = settings.subagentsEnabled;
1180
+ }
1181
+ if (settings.localizationTargets !== void 0) {
1182
+ body.localization_targets = settings.localizationTargets;
1183
+ }
1184
+ return this._post("/configuration/system/settings", body);
1031
1185
  }
1032
1186
  async getConfigurationStatus() {
1033
1187
  return this._get("/configuration/status");
@@ -1047,9 +1201,7 @@ var OrchestratorAsync = class {
1047
1201
  return { message: data.message ?? "" };
1048
1202
  }
1049
1203
  async getLLMBackendStatus() {
1050
- return this._get(
1051
- "/configuration/llmbackend/status"
1052
- );
1204
+ return this._get("/configuration/llmbackend/status");
1053
1205
  }
1054
1206
  async addLLMBackend(host, apiKey) {
1055
1207
  const data = await this._post(
@@ -1066,9 +1218,7 @@ var OrchestratorAsync = class {
1066
1218
  return { message: data.message ?? "" };
1067
1219
  }
1068
1220
  async getMCPServerStatus() {
1069
- return this._get(
1070
- "/configuration/mcpserver/status"
1071
- );
1221
+ return this._get("/configuration/mcpserver/status");
1072
1222
  }
1073
1223
  async addMCPServer(host, apiKey) {
1074
1224
  const data = await this._post(
@@ -1257,8 +1407,8 @@ var Orchestrator = class {
1257
1407
  // ------------------------------------------------------------------
1258
1408
  // Attachments
1259
1409
  // ------------------------------------------------------------------
1260
- uploadAttachment(file, filename) {
1261
- return runSync(this._async.uploadAttachment(file, filename));
1410
+ uploadAttachment(file, filename, options) {
1411
+ return runSync(this._async.uploadAttachment(file, filename, options));
1262
1412
  }
1263
1413
  downloadAttachment(attachmentId) {
1264
1414
  return runSync(this._async.downloadAttachment(attachmentId));
@@ -1459,8 +1609,8 @@ var Orchestrator = class {
1459
1609
  getErrorStats(since) {
1460
1610
  return runSync(this._async.getErrorStats(since));
1461
1611
  }
1462
- countErrors(since) {
1463
- return runSync(this._async.countErrors(since));
1612
+ countErrors(since, severity) {
1613
+ return runSync(this._async.countErrors(since, severity));
1464
1614
  }
1465
1615
  purgeErrors() {
1466
1616
  return runSync(this._async.purgeErrors());
@@ -1763,12 +1913,18 @@ var RealtimeClient = class {
1763
1913
  /**
1764
1914
  * Dispatch a message envelope to registered handlers and subscribers.
1765
1915
  * The server sends: socket.emit("message", {type: "message", event: {..., event_type: "...", ...}})
1916
+ *
1917
+ * All event payloads are deep-converted from snake_case to camelCase so
1918
+ * consumers receive consistent camelCase objects (same convention as the
1919
+ * REST responses from _request). The raw event_type string is extracted
1920
+ * before conversion so the handler-map lookup still works.
1766
1921
  */
1767
1922
  _dispatch(payload) {
1768
1923
  const envelope = payload;
1769
- const event = envelope.event ?? envelope;
1770
- const eventType = event.event_type;
1924
+ const rawEvent = envelope.event ?? envelope;
1925
+ const eventType = rawEvent.event_type;
1771
1926
  if (!eventType) return;
1927
+ const event = deepCamelCase(rawEvent);
1772
1928
  const handlers = this._handlers.get(eventType);
1773
1929
  if (handlers) {
1774
1930
  for (const h of handlers) {
@@ -1977,10 +2133,303 @@ var RealtimeClient = class {
1977
2133
  }
1978
2134
  };
1979
2135
 
2136
+ // src/flow.ts
2137
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
2138
+ "completed",
2139
+ "failed",
2140
+ "cancelled",
2141
+ "translation"
2142
+ ]);
2143
+ var DEFAULT_FLOW_TIMEOUT_MS = 6e5;
2144
+ var _defaultClient;
2145
+ var _defaultRealtime;
2146
+ function setupDefaultClient(client, realtime) {
2147
+ _defaultClient = client;
2148
+ _defaultRealtime = realtime;
2149
+ }
2150
+ function getDefaultClient() {
2151
+ if (!_defaultClient) {
2152
+ throw new Error(
2153
+ "No default OrchestratorAsync set. Call setupDefaultClient() during application startup, or pass client to flow.run()."
2154
+ );
2155
+ }
2156
+ return _defaultClient;
2157
+ }
2158
+ function getDefaultRealtime() {
2159
+ return _defaultRealtime;
2160
+ }
2161
+ var FlowError = class extends Error {
2162
+ constructor(message) {
2163
+ super(message);
2164
+ this.name = "FlowError";
2165
+ }
2166
+ };
2167
+ var FlowTimeoutError = class extends FlowError {
2168
+ constructor(message) {
2169
+ super(message);
2170
+ this.name = "FlowTimeoutError";
2171
+ }
2172
+ };
2173
+ var FlowCancelledError = class extends FlowError {
2174
+ constructor(taskId) {
2175
+ super(`Task ${taskId} was cancelled`);
2176
+ this.name = "FlowCancelledError";
2177
+ this.taskId = taskId;
2178
+ }
2179
+ };
2180
+ function extractJsonFromMessage(content) {
2181
+ const cleaned = content.replace(/^\ufeff|\u200b|\u200c|\u200d/, "").trim();
2182
+ if (cleaned.startsWith("{")) {
2183
+ try {
2184
+ return JSON.parse(cleaned);
2185
+ } catch {
2186
+ }
2187
+ }
2188
+ const start = content.indexOf("{");
2189
+ const end = content.lastIndexOf("}");
2190
+ if (start !== -1 && end !== -1 && end > start) {
2191
+ try {
2192
+ return JSON.parse(content.slice(start, end + 1));
2193
+ } catch {
2194
+ }
2195
+ }
2196
+ const jsonFenceMatch = content.match(/```(?:json)\s*\n([\s\S]*?)\n```/i);
2197
+ if (jsonFenceMatch) {
2198
+ try {
2199
+ return JSON.parse(jsonFenceMatch[1].trim());
2200
+ } catch {
2201
+ }
2202
+ }
2203
+ const anyFenceMatch = content.match(/```(?:[\w]*)\s*\n([\s\S]*?)\n```/);
2204
+ if (anyFenceMatch) {
2205
+ try {
2206
+ return JSON.parse(anyFenceMatch[1].trim());
2207
+ } catch {
2208
+ }
2209
+ }
2210
+ const bareBraceMatch = content.match(/\{[\s\S]*\}/);
2211
+ if (bareBraceMatch) {
2212
+ try {
2213
+ return JSON.parse(bareBraceMatch[0]);
2214
+ } catch {
2215
+ }
2216
+ }
2217
+ throw new FlowError(
2218
+ "Could not extract a valid JSON object from the agent's final message. The agent did not format its answer as required."
2219
+ );
2220
+ }
2221
+ var Flow = class {
2222
+ constructor() {
2223
+ // -- Workflow-level defaults (override in subclass) --------------------
2224
+ /** Orchestrator workflow type — `"proactive"` by default. */
2225
+ this.workflowId = "proactive";
2226
+ /** Maximum agent turns before the orchestrator forces a failure. */
2227
+ this.maxIterations = 100;
2228
+ /** LLM reasoning budget: `"low"`, `"medium"`, or `"high"`. */
2229
+ this.reasoningEffort = "medium";
2230
+ /**
2231
+ * Maximum milliseconds to wait for the orchestrator task to reach a
2232
+ * terminal state. When exceeded, {@link FlowTimeoutError} is raised.
2233
+ */
2234
+ this.flowTimeoutMs = DEFAULT_FLOW_TIMEOUT_MS;
2235
+ }
2236
+ /**
2237
+ * Optional system-prompt override.
2238
+ * When set, this replaces the orchestrator's default system prompt.
2239
+ */
2240
+ get systemPrompt() {
2241
+ return void 0;
2242
+ }
2243
+ /**
2244
+ * Optional developer-prompt override appended after system prompt.
2245
+ */
2246
+ get developerPrompt() {
2247
+ return void 0;
2248
+ }
2249
+ /**
2250
+ * Restrict which MCP / built-in tools the agent may use.
2251
+ * `undefined` means *all* tools are available. An empty array means
2252
+ * *no* tools — text-only reasoning.
2253
+ */
2254
+ get availableTools() {
2255
+ return void 0;
2256
+ }
2257
+ /**
2258
+ * Per-task feature toggles sent in the creation request.
2259
+ * By default summaries and translation are disabled since flow
2260
+ * output is typically machine-consumed, not human-read.
2261
+ * Override in subclasses that produce human-facing content.
2262
+ */
2263
+ get taskOptions() {
2264
+ return { disableSummaries: true, disableTranslation: true };
2265
+ }
2266
+ /**
2267
+ * Override the agent model for this flow.
2268
+ */
2269
+ get agentModelId() {
2270
+ return void 0;
2271
+ }
2272
+ /**
2273
+ * Override the orchestrator (validation) model for this flow.
2274
+ */
2275
+ get orchestratorModelId() {
2276
+ return void 0;
2277
+ }
2278
+ /**
2279
+ * Cancel the underlying orchestrator task, if one is running.
2280
+ *
2281
+ * Calling `cancel()` after `run()` has returned is a no-op.
2282
+ * The `run()` promise will reject with {@link FlowCancelledError}
2283
+ * after the orchestrator task transitions to `"cancelled"`.
2284
+ */
2285
+ async cancel(client) {
2286
+ if (!this._lastTaskId) return;
2287
+ const resolvedClient = client ?? getDefaultClient();
2288
+ await resolvedClient.cancelTask(this._lastTaskId);
2289
+ }
2290
+ // -- Lifecycle ---------------------------------------------------------
2291
+ /**
2292
+ * Execute the flow end-to-end.
2293
+ *
2294
+ * @returns The parsed result.
2295
+ * @throws {FlowError} If the task fails, times out, or cannot be parsed.
2296
+ */
2297
+ async run(params) {
2298
+ const client = params?.client ?? getDefaultClient();
2299
+ const realtime = params?.realtime ?? getDefaultRealtime();
2300
+ const timeoutMs = params?.timeoutMs ?? this.flowTimeoutMs;
2301
+ console.log(
2302
+ `[Flow] Starting ${this.constructor.name} \u2014 workflow=${this.workflowId} goal=${this.goalPrompt.slice(0, 80)}`
2303
+ );
2304
+ const response = await client.createTask({
2305
+ workflowId: this.workflowId,
2306
+ goalPrompt: this.goalPrompt,
2307
+ systemPrompt: this.systemPrompt,
2308
+ developerPrompt: this.developerPrompt,
2309
+ availableTools: this.availableTools,
2310
+ options: this.taskOptions,
2311
+ maxIterations: this.maxIterations,
2312
+ reasoningEffort: this.reasoningEffort,
2313
+ agentModelId: this.agentModelId,
2314
+ orchestratorModelId: this.orchestratorModelId
2315
+ });
2316
+ this._lastTaskId = response.taskId;
2317
+ const taskId = response.taskId;
2318
+ console.log(
2319
+ `[Flow] Task created \u2014 taskId=${taskId} status=${response.status}`
2320
+ );
2321
+ const status = await this._waitForTerminal(client, taskId, {
2322
+ realtime,
2323
+ timeoutMs
2324
+ });
2325
+ if (status.status === "cancelled") {
2326
+ throw new FlowCancelledError(taskId);
2327
+ }
2328
+ const finalMessage = await this._getFinalMessage(client, taskId);
2329
+ console.log(
2330
+ `[Flow] ${this.constructor.name} completed \u2014 taskId=${taskId} messageLen=${finalMessage.length}`
2331
+ );
2332
+ return this.parseResult(finalMessage);
2333
+ }
2334
+ // -- Completion waiting -----------------------------------------------
2335
+ async _waitForTerminal(client, taskId, opts) {
2336
+ const { realtime, timeoutMs } = opts;
2337
+ const status = await client.getTaskStatus(taskId);
2338
+ if (TERMINAL_STATUSES.has(status.status)) {
2339
+ console.log(
2340
+ `[Flow] Task ${taskId} already terminal \u2014 status=${status.status}`
2341
+ );
2342
+ return status;
2343
+ }
2344
+ if (realtime) {
2345
+ await this._waitViaSocketIO(taskId, realtime, timeoutMs);
2346
+ } else {
2347
+ console.log(
2348
+ `[Flow] No RealtimeClient available \u2014 polling task ${taskId} with backoff (timeout=${timeoutMs}ms)`
2349
+ );
2350
+ await this._waitViaPolling(client, taskId, timeoutMs);
2351
+ }
2352
+ return client.getTaskStatus(taskId);
2353
+ }
2354
+ async _waitViaSocketIO(taskId, realtime, timeoutMs) {
2355
+ realtime.subscribeTask(taskId);
2356
+ return new Promise((resolve, reject) => {
2357
+ const timer = setTimeout(() => {
2358
+ cleanup();
2359
+ reject(
2360
+ new FlowTimeoutError(
2361
+ `Task ${taskId} did not reach a terminal state within ${timeoutMs}ms`
2362
+ )
2363
+ );
2364
+ }, timeoutMs);
2365
+ const handler = (...args) => {
2366
+ const event = args[0] ?? {};
2367
+ if (event.task_id !== taskId) return;
2368
+ const newStatus = event.new_status ?? "";
2369
+ if (TERMINAL_STATUSES.has(newStatus)) {
2370
+ cleanup();
2371
+ resolve();
2372
+ }
2373
+ };
2374
+ const cleanup = () => {
2375
+ clearTimeout(timer);
2376
+ realtime.off("task_status_changed", handler);
2377
+ realtime.unsubscribeTask(taskId);
2378
+ };
2379
+ realtime.on("task_status_changed", handler);
2380
+ });
2381
+ }
2382
+ async _waitViaPolling(client, taskId, timeoutMs) {
2383
+ const deadline = Date.now() + timeoutMs;
2384
+ let delay = 1e3;
2385
+ while (Date.now() < deadline) {
2386
+ const status = await client.getTaskStatus(taskId);
2387
+ if (TERMINAL_STATUSES.has(status.status)) return;
2388
+ await this._sleep(delay);
2389
+ delay = Math.min(Math.round(delay * 1.5), 1e4);
2390
+ }
2391
+ throw new FlowTimeoutError(
2392
+ `Task ${taskId} did not reach a terminal state within ${timeoutMs}ms (polling fallback)`
2393
+ );
2394
+ }
2395
+ // -- Conversation helpers ---------------------------------------------
2396
+ async _getFinalMessage(client, taskId) {
2397
+ const conversation = await client.getTaskConversation(taskId, {
2398
+ includeSummaries: false,
2399
+ excludeArchived: false
2400
+ });
2401
+ const messages = conversation.conversation;
2402
+ for (let i = messages.length - 1; i >= 0; i--) {
2403
+ const msg = messages[i];
2404
+ if (msg.role === "assistant" && msg.content?.trim()) {
2405
+ return msg.content;
2406
+ }
2407
+ }
2408
+ for (let i = messages.length - 1; i >= 0; i--) {
2409
+ const msg = messages[i];
2410
+ if (msg.role === "assistant" && msg.archived && msg.id != null) {
2411
+ const archived = await client.getArchivedMessageContent(taskId, msg.id);
2412
+ if (archived.content?.trim()) {
2413
+ return archived.content;
2414
+ }
2415
+ }
2416
+ }
2417
+ const status = await client.getTaskStatus(taskId);
2418
+ throw new FlowError(
2419
+ `No assistant message with content found in task ${taskId}. Status: ${status.status}. Result: ${(status.result ?? "").slice(0, 200) || "empty"}. Messages in conversation: ${messages.length}.`
2420
+ );
2421
+ }
2422
+ // -- Helper -----------------------------------------------------------
2423
+ _sleep(ms) {
2424
+ return new Promise((resolve) => setTimeout(resolve, ms));
2425
+ }
2426
+ };
2427
+
1980
2428
  // src/index.ts
1981
2429
  var VERSION = "5.6.0";
1982
2430
  // Annotate the CommonJS export names for ESM import in node:
1983
2431
  0 && (module.exports = {
2432
+ DEFAULT_FLOW_TIMEOUT_MS,
1984
2433
  EVENT_ERROR_EVENT_RECORDED,
1985
2434
  EVENT_MESSAGE_ADDED,
1986
2435
  EVENT_MESSAGE_STREAMING,
@@ -1992,6 +2441,10 @@ var VERSION = "5.6.0";
1992
2441
  EVENT_TASK_ITERATION_CHANGED,
1993
2442
  EVENT_TASK_RESULT_UPDATED,
1994
2443
  EVENT_TASK_STATUS_CHANGED,
2444
+ Flow,
2445
+ FlowCancelledError,
2446
+ FlowError,
2447
+ FlowTimeoutError,
1995
2448
  Orchestrator,
1996
2449
  OrchestratorAPIError,
1997
2450
  OrchestratorAsync,
@@ -2002,7 +2455,12 @@ var VERSION = "5.6.0";
2002
2455
  OrchestratorNotFoundError,
2003
2456
  RealtimeClient,
2004
2457
  VERSION,
2458
+ camelToSnake,
2005
2459
  createInsecureFetch,
2006
- loadConfig
2460
+ deepCamelCase,
2461
+ extractJsonFromMessage,
2462
+ loadConfig,
2463
+ setupDefaultClient,
2464
+ snakeToCamel
2007
2465
  });
2008
2466
  //# sourceMappingURL=index.cjs.map