orchestrator-client 5.7.3 → 5.7.4

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
@@ -51,8 +51,11 @@ __export(index_exports, {
51
51
  OrchestratorNotFoundError: () => OrchestratorNotFoundError,
52
52
  RealtimeClient: () => RealtimeClient,
53
53
  VERSION: () => VERSION,
54
+ camelToSnake: () => camelToSnake,
54
55
  createInsecureFetch: () => createInsecureFetch,
55
- loadConfig: () => loadConfig
56
+ deepCamelCase: () => deepCamelCase,
57
+ loadConfig: () => loadConfig,
58
+ snakeToCamel: () => snakeToCamel
56
59
  });
57
60
  module.exports = __toCommonJS(index_exports);
58
61
 
@@ -73,8 +76,8 @@ var OrchestratorConnectionError = class extends OrchestratorError {
73
76
  }
74
77
  };
75
78
  var OrchestratorAuthError = class extends OrchestratorError {
76
- constructor(message, statusCode = 401) {
77
- super(message, { statusCode });
79
+ constructor(message, statusCode = 401, errorCode) {
80
+ super(message, { statusCode, errorCode });
78
81
  this.name = "OrchestratorAuthError";
79
82
  }
80
83
  };
@@ -101,6 +104,28 @@ var OrchestratorConfigError = class extends OrchestratorError {
101
104
  }
102
105
  };
103
106
 
107
+ // src/utils.ts
108
+ function snakeToCamel(str) {
109
+ return str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
110
+ }
111
+ function camelToSnake(str) {
112
+ return str.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
113
+ }
114
+ function deepCamelCase(obj) {
115
+ if (Array.isArray(obj)) {
116
+ return obj.map(deepCamelCase);
117
+ }
118
+ if (typeof obj === "object" && obj !== null) {
119
+ return Object.fromEntries(
120
+ Object.entries(obj).map(([key, value]) => [
121
+ snakeToCamel(key),
122
+ deepCamelCase(value)
123
+ ])
124
+ );
125
+ }
126
+ return obj;
127
+ }
128
+
104
129
  // src/client.ts
105
130
  var RETRY_BACKOFF_BASE = 500;
106
131
  var DEFAULT_TIMEOUT_MS = 3e4;
@@ -120,22 +145,66 @@ function buildTaskSummary(t) {
120
145
  return {
121
146
  id: t.id ?? "",
122
147
  status: t.status ?? "",
123
- workflowId: t.workflowId ?? t.workflow_id ?? "",
148
+ workflowId: t.workflowId ?? "",
124
149
  iteration: t.iteration ?? 0,
125
- maxIterations: t.maxIterations ?? t.max_iterations ?? 0,
126
- goalPrompt: t.goalPrompt ?? t.goal_prompt ?? "",
150
+ maxIterations: t.maxIterations ?? 0,
151
+ goalPrompt: t.goalPrompt ?? "",
127
152
  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,
153
+ resultLocalized: t.resultLocalized ?? null,
154
+ approvalReason: t.approvalReason ?? "",
155
+ ticketId: t.ticketId ?? null,
156
+ availableTools: t.availableTools ?? null,
132
157
  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
158
+ insightLocalized: t.insightLocalized ?? null,
159
+ createdAt: t.createdAt ?? "",
160
+ updatedAt: t.updatedAt ?? "",
161
+ pendingTranslationsForLocales: t.pendingTranslationsForLocales ?? null
137
162
  };
138
163
  }
164
+ function parseApiErrorBody(body, fallbackMessage) {
165
+ let errorCode = body.error_code ?? null;
166
+ if (!errorCode && body.error && typeof body.error === "object") {
167
+ const nested = body.error;
168
+ errorCode = nested.code ?? null;
169
+ }
170
+ let message = null;
171
+ if (typeof body.error === "string") {
172
+ message = body.error;
173
+ } else if (typeof body.message === "string") {
174
+ message = body.message;
175
+ }
176
+ let details = body.details ?? null;
177
+ const detail = body.detail;
178
+ if (typeof detail === "string") {
179
+ message = detail;
180
+ } else if (detail && typeof detail === "object" && !Array.isArray(detail)) {
181
+ const detailObj = detail;
182
+ if (!errorCode) {
183
+ errorCode = detailObj.error_code ?? null;
184
+ }
185
+ if (typeof detailObj.error === "string") {
186
+ message = detailObj.error;
187
+ } else if (typeof detailObj.message === "string") {
188
+ message = detailObj.message;
189
+ }
190
+ if (!details) {
191
+ details = detailObj;
192
+ }
193
+ }
194
+ if (!message) {
195
+ message = fallbackMessage;
196
+ }
197
+ const missingFields = body.missing_fields;
198
+ if (Array.isArray(missingFields) && missingFields.length > 0) {
199
+ const fields = missingFields.filter(
200
+ (f) => typeof f === "string"
201
+ );
202
+ if (fields.length > 0) {
203
+ message = `${message} (missing: ${fields.join(", ")})`;
204
+ }
205
+ }
206
+ return { message, errorCode, details };
207
+ }
139
208
  var OrchestratorAsync = class {
140
209
  constructor(opts = {}) {
141
210
  this._abortController = null;
@@ -149,7 +218,7 @@ var OrchestratorAsync = class {
149
218
  this._timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
150
219
  this._maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
151
220
  this._locale = opts.locale;
152
- this._fetch = opts.fetch ?? globalThis.fetch;
221
+ this._fetch = opts.fetch ?? globalThis.fetch.bind(globalThis);
153
222
  if (opts.insecure && !opts.fetch && typeof process !== "undefined" && process.versions?.node) {
154
223
  this._insecure = true;
155
224
  }
@@ -207,16 +276,21 @@ var OrchestratorAsync = class {
207
276
  signal
208
277
  });
209
278
  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) {
279
+ if (response.status === 401 || response.status === 403) {
280
+ const defaultAuthMsg = response.status === 401 ? `Authentication failed for ${method} ${path}` : `Access denied for ${method} ${path}`;
281
+ let authErrorCode = null;
282
+ let authErrorMsg = defaultAuthMsg;
283
+ try {
284
+ const body = await response.clone().json();
285
+ const parsed = parseApiErrorBody(body, defaultAuthMsg);
286
+ authErrorMsg = parsed.message;
287
+ authErrorCode = parsed.errorCode;
288
+ } catch {
289
+ }
217
290
  throw new OrchestratorAuthError(
218
- `Access denied for ${method} ${path}`,
219
- 403
291
+ authErrorMsg,
292
+ response.status,
293
+ authErrorCode
220
294
  );
221
295
  }
222
296
  if (response.status === 404) {
@@ -243,21 +317,27 @@ var OrchestratorAsync = class {
243
317
  if (response.ok) {
244
318
  const contentType = response.headers.get("content-type") ?? "";
245
319
  if (contentType.includes("application/json")) {
246
- return response.json();
320
+ return deepCamelCase(await response.json());
247
321
  }
248
322
  return { _text: await response.text() };
249
323
  }
250
- let errorMessage;
324
+ const defaultMessage = `API Error with status ${response.status}`;
325
+ let errorMessage = defaultMessage;
251
326
  let errorCode = null;
252
327
  let errorDetails = null;
253
328
  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;
329
+ const clonedResponse = response.clone();
330
+ const body = await clonedResponse.json();
331
+ const parsed = parseApiErrorBody(body, JSON.stringify(body));
332
+ errorMessage = parsed.message;
333
+ errorCode = parsed.errorCode;
334
+ errorDetails = parsed.details;
259
335
  } catch {
260
- errorMessage = await response.text();
336
+ try {
337
+ errorMessage = await response.text();
338
+ } catch {
339
+ errorMessage = defaultMessage;
340
+ }
261
341
  }
262
342
  throw new OrchestratorAPIError(
263
343
  errorMessage,
@@ -327,7 +407,7 @@ var OrchestratorAsync = class {
327
407
  params: {
328
408
  page: params?.page,
329
409
  limit: params?.limit,
330
- order_by: params?.orderBy,
410
+ order_by: params?.orderBy ? camelToSnake(params.orderBy) : void 0,
331
411
  order_direction: params?.orderDirection,
332
412
  workflow_id: params?.workflowId
333
413
  },
@@ -400,10 +480,10 @@ var OrchestratorAsync = class {
400
480
  };
401
481
  }
402
482
  async getArchivedMessageContent(taskId, messageId) {
403
- return this._get(
404
- "/task/message/archived-content",
405
- { task_id: taskId, message_id: messageId }
406
- );
483
+ return this._get("/task/message/archived-content", {
484
+ task_id: taskId,
485
+ message_id: messageId
486
+ });
407
487
  }
408
488
  async getTaskCompactions(taskId) {
409
489
  return this._get("/task/compactions", {
@@ -462,19 +542,39 @@ var OrchestratorAsync = class {
462
542
  // ------------------------------------------------------------------
463
543
  // Attachments
464
544
  // ------------------------------------------------------------------
465
- async uploadAttachment(file, filename) {
545
+ async uploadAttachment(file, filename, options) {
466
546
  const formData = new FormData();
467
547
  formData.append("file", file, filename);
468
548
  const headers = await this._resolveHeaders();
469
549
  const response = await this._fetch(this._makeUrl("/attachment"), {
470
550
  method: "POST",
471
551
  headers: { ...headers },
472
- body: formData
552
+ body: formData,
553
+ signal: options?.signal
473
554
  });
474
555
  if (!response.ok) {
556
+ const defaultMessage = `Attachment upload failed: ${response.statusText}`;
557
+ let errorMessage = defaultMessage;
558
+ let errorCode = null;
559
+ let errorDetails = null;
560
+ try {
561
+ const body = await response.clone().json();
562
+ const parsed = parseApiErrorBody(body, defaultMessage);
563
+ errorMessage = parsed.message;
564
+ errorCode = parsed.errorCode;
565
+ errorDetails = parsed.details;
566
+ } catch {
567
+ try {
568
+ errorMessage = await response.text() || defaultMessage;
569
+ } catch {
570
+ errorMessage = defaultMessage;
571
+ }
572
+ }
475
573
  throw new OrchestratorAPIError(
476
- `Attachment upload failed: ${response.statusText}`,
477
- response.status
574
+ errorMessage,
575
+ response.status,
576
+ errorCode,
577
+ errorDetails ?? void 0
478
578
  );
479
579
  }
480
580
  const data = await response.json();
@@ -992,10 +1092,24 @@ var OrchestratorAsync = class {
992
1092
  if (since) params.since = since;
993
1093
  return this._get("/errors/stats", params);
994
1094
  }
995
- async countErrors(since) {
996
- const params = {};
997
- if (since) params.since = since;
998
- return this._get("/errors/count", params);
1095
+ async countErrors(since, severity) {
1096
+ const authHeaders = await this._resolveHeaders();
1097
+ const url = new URL(this._makeUrl("/errors/count"));
1098
+ if (since) url.searchParams.set("since", since);
1099
+ for (const s of severity ?? []) {
1100
+ url.searchParams.append("severity", s);
1101
+ }
1102
+ const response = await this._fetch(url.toString(), {
1103
+ method: "GET",
1104
+ headers: { ...authHeaders }
1105
+ });
1106
+ if (!response.ok) {
1107
+ throw new OrchestratorAPIError(
1108
+ `countErrors failed: ${response.statusText}`,
1109
+ response.status
1110
+ );
1111
+ }
1112
+ return deepCamelCase(await response.json());
999
1113
  }
1000
1114
  async purgeErrors() {
1001
1115
  return this._delete("/errors");
@@ -1027,7 +1141,35 @@ var OrchestratorAsync = class {
1027
1141
  return this._get("/configuration/system/status");
1028
1142
  }
1029
1143
  async updateSettings(settings) {
1030
- return this._post("/configuration/system/settings", settings);
1144
+ const body = {};
1145
+ if (settings.agentModelId !== void 0) {
1146
+ body.agent_model_id = settings.agentModelId;
1147
+ }
1148
+ if (settings.orchestratorModelId !== void 0) {
1149
+ body.orchestrator_model_id = settings.orchestratorModelId;
1150
+ }
1151
+ if (settings.compactorModelId !== void 0) {
1152
+ body.compactor_model_id = settings.compactorModelId;
1153
+ }
1154
+ if (settings.journalModelId !== void 0) {
1155
+ body.journal_model_id = settings.journalModelId;
1156
+ }
1157
+ if (settings.summaryModelId !== void 0) {
1158
+ body.summary_model_id = settings.summaryModelId;
1159
+ }
1160
+ if (settings.translateModelId !== void 0) {
1161
+ body.translate_model_id = settings.translateModelId;
1162
+ }
1163
+ if (settings.maxConcurrentTasksPerReplica !== void 0) {
1164
+ body.max_concurrent_tasks_per_replica = settings.maxConcurrentTasksPerReplica;
1165
+ }
1166
+ if (settings.subagentsEnabled !== void 0) {
1167
+ body.subagents_enabled = settings.subagentsEnabled;
1168
+ }
1169
+ if (settings.localizationTargets !== void 0) {
1170
+ body.localization_targets = settings.localizationTargets;
1171
+ }
1172
+ return this._post("/configuration/system/settings", body);
1031
1173
  }
1032
1174
  async getConfigurationStatus() {
1033
1175
  return this._get("/configuration/status");
@@ -1047,9 +1189,7 @@ var OrchestratorAsync = class {
1047
1189
  return { message: data.message ?? "" };
1048
1190
  }
1049
1191
  async getLLMBackendStatus() {
1050
- return this._get(
1051
- "/configuration/llmbackend/status"
1052
- );
1192
+ return this._get("/configuration/llmbackend/status");
1053
1193
  }
1054
1194
  async addLLMBackend(host, apiKey) {
1055
1195
  const data = await this._post(
@@ -1066,9 +1206,7 @@ var OrchestratorAsync = class {
1066
1206
  return { message: data.message ?? "" };
1067
1207
  }
1068
1208
  async getMCPServerStatus() {
1069
- return this._get(
1070
- "/configuration/mcpserver/status"
1071
- );
1209
+ return this._get("/configuration/mcpserver/status");
1072
1210
  }
1073
1211
  async addMCPServer(host, apiKey) {
1074
1212
  const data = await this._post(
@@ -1257,8 +1395,8 @@ var Orchestrator = class {
1257
1395
  // ------------------------------------------------------------------
1258
1396
  // Attachments
1259
1397
  // ------------------------------------------------------------------
1260
- uploadAttachment(file, filename) {
1261
- return runSync(this._async.uploadAttachment(file, filename));
1398
+ uploadAttachment(file, filename, options) {
1399
+ return runSync(this._async.uploadAttachment(file, filename, options));
1262
1400
  }
1263
1401
  downloadAttachment(attachmentId) {
1264
1402
  return runSync(this._async.downloadAttachment(attachmentId));
@@ -1459,8 +1597,8 @@ var Orchestrator = class {
1459
1597
  getErrorStats(since) {
1460
1598
  return runSync(this._async.getErrorStats(since));
1461
1599
  }
1462
- countErrors(since) {
1463
- return runSync(this._async.countErrors(since));
1600
+ countErrors(since, severity) {
1601
+ return runSync(this._async.countErrors(since, severity));
1464
1602
  }
1465
1603
  purgeErrors() {
1466
1604
  return runSync(this._async.purgeErrors());
@@ -1763,12 +1901,18 @@ var RealtimeClient = class {
1763
1901
  /**
1764
1902
  * Dispatch a message envelope to registered handlers and subscribers.
1765
1903
  * The server sends: socket.emit("message", {type: "message", event: {..., event_type: "...", ...}})
1904
+ *
1905
+ * All event payloads are deep-converted from snake_case to camelCase so
1906
+ * consumers receive consistent camelCase objects (same convention as the
1907
+ * REST responses from _request). The raw event_type string is extracted
1908
+ * before conversion so the handler-map lookup still works.
1766
1909
  */
1767
1910
  _dispatch(payload) {
1768
1911
  const envelope = payload;
1769
- const event = envelope.event ?? envelope;
1770
- const eventType = event.event_type;
1912
+ const rawEvent = envelope.event ?? envelope;
1913
+ const eventType = rawEvent.event_type;
1771
1914
  if (!eventType) return;
1915
+ const event = deepCamelCase(rawEvent);
1772
1916
  const handlers = this._handlers.get(eventType);
1773
1917
  if (handlers) {
1774
1918
  for (const h of handlers) {
@@ -2002,7 +2146,10 @@ var VERSION = "5.6.0";
2002
2146
  OrchestratorNotFoundError,
2003
2147
  RealtimeClient,
2004
2148
  VERSION,
2149
+ camelToSnake,
2005
2150
  createInsecureFetch,
2006
- loadConfig
2151
+ deepCamelCase,
2152
+ loadConfig,
2153
+ snakeToCamel
2007
2154
  });
2008
2155
  //# sourceMappingURL=index.cjs.map