orchestrator-client 5.7.4 → 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,
@@ -54,7 +59,9 @@ __export(index_exports, {
54
59
  camelToSnake: () => camelToSnake,
55
60
  createInsecureFetch: () => createInsecureFetch,
56
61
  deepCamelCase: () => deepCamelCase,
62
+ extractJsonFromMessage: () => extractJsonFromMessage,
57
63
  loadConfig: () => loadConfig,
64
+ setupDefaultClient: () => setupDefaultClient,
58
65
  snakeToCamel: () => snakeToCamel
59
66
  });
60
67
  module.exports = __toCommonJS(index_exports);
@@ -232,6 +239,11 @@ var OrchestratorAsync = class {
232
239
  _makeUrl(path) {
233
240
  return `${this._baseUrl}${path}`;
234
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
+ }
235
247
  async _resolveHeaders() {
236
248
  const headers = {};
237
249
  if (this._apiKey) {
@@ -248,7 +260,7 @@ var OrchestratorAsync = class {
248
260
  return headers;
249
261
  }
250
262
  async _request(method, path, opts) {
251
- const url = new URL(this._makeUrl(path));
263
+ const url = this._makeAbsoluteUrl(path);
252
264
  if (opts?.params) {
253
265
  for (const [key, value] of Object.entries(opts.params)) {
254
266
  if (value !== void 0) {
@@ -1042,7 +1054,7 @@ var OrchestratorAsync = class {
1042
1054
  // ------------------------------------------------------------------
1043
1055
  async listErrors(params) {
1044
1056
  const authHeaders = await this._resolveHeaders();
1045
- const url = new URL(this._makeUrl("/errors"));
1057
+ const url = this._makeAbsoluteUrl("/errors");
1046
1058
  if (params?.page !== void 0)
1047
1059
  url.searchParams.set("page", String(params.page));
1048
1060
  if (params?.limit !== void 0)
@@ -2121,10 +2133,303 @@ var RealtimeClient = class {
2121
2133
  }
2122
2134
  };
2123
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
+
2124
2428
  // src/index.ts
2125
2429
  var VERSION = "5.6.0";
2126
2430
  // Annotate the CommonJS export names for ESM import in node:
2127
2431
  0 && (module.exports = {
2432
+ DEFAULT_FLOW_TIMEOUT_MS,
2128
2433
  EVENT_ERROR_EVENT_RECORDED,
2129
2434
  EVENT_MESSAGE_ADDED,
2130
2435
  EVENT_MESSAGE_STREAMING,
@@ -2136,6 +2441,10 @@ var VERSION = "5.6.0";
2136
2441
  EVENT_TASK_ITERATION_CHANGED,
2137
2442
  EVENT_TASK_RESULT_UPDATED,
2138
2443
  EVENT_TASK_STATUS_CHANGED,
2444
+ Flow,
2445
+ FlowCancelledError,
2446
+ FlowError,
2447
+ FlowTimeoutError,
2139
2448
  Orchestrator,
2140
2449
  OrchestratorAPIError,
2141
2450
  OrchestratorAsync,
@@ -2149,7 +2458,9 @@ var VERSION = "5.6.0";
2149
2458
  camelToSnake,
2150
2459
  createInsecureFetch,
2151
2460
  deepCamelCase,
2461
+ extractJsonFromMessage,
2152
2462
  loadConfig,
2463
+ setupDefaultClient,
2153
2464
  snakeToCamel
2154
2465
  });
2155
2466
  //# sourceMappingURL=index.cjs.map