opencode-orchestrator 1.2.15 → 1.2.17

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.
@@ -5,5 +5,6 @@ export declare const CONFIG: {
5
5
  readonly TASK_TTL_MS: number;
6
6
  readonly CLEANUP_DELAY_MS: number;
7
7
  readonly MIN_STABILITY_MS: number;
8
- readonly POLL_INTERVAL_MS: 2000;
8
+ readonly POLL_INTERVAL_MS: 5000;
9
+ readonly STABLE_POLLS_REQUIRED: 2;
9
10
  };
@@ -15,12 +15,13 @@ export declare class TaskPoller {
15
15
  private pruneExpiredTasks;
16
16
  private onTaskComplete?;
17
17
  private onTaskError?;
18
- private pollingInterval?;
18
+ private pollTimeout?;
19
19
  private messageCache;
20
20
  constructor(client: OpencodeClient, store: TaskStore, concurrency: ConcurrencyController, notifyParentIfAllComplete: (parentSessionID: string) => Promise<void>, scheduleCleanup: (taskId: string) => void, pruneExpiredTasks: () => void, onTaskComplete?: ((task: ParallelTask) => void | Promise<void>) | undefined, onTaskError?: ((taskId: string, error: unknown) => void) | undefined);
21
21
  start(): void;
22
22
  stop(): void;
23
23
  isRunning(): boolean;
24
+ private scheduleNextPoll;
24
25
  poll(): Promise<void>;
25
26
  validateSessionHasOutput(sessionID: string, task?: ParallelTask): Promise<boolean>;
26
27
  completeTask(task: ParallelTask): Promise<void>;
package/dist/index.js CHANGED
@@ -501,21 +501,23 @@ var init_parallel_task = __esm({
501
501
  */
502
502
  TERMINAL_DEPTH: 2,
503
503
  // Concurrency limits (Aggressive for intense processing)
504
- DEFAULT_CONCURRENCY: 10,
505
- MAX_CONCURRENCY: 50,
504
+ DEFAULT_CONCURRENCY: 3,
505
+ // Reduced from 10
506
+ MAX_CONCURRENCY: 5,
507
+ // Reduced from 50
506
508
  // Sync polling (for delegate_task sync mode)
507
509
  // Optimized: Reduced polling frequency while relying more on events
508
510
  SYNC_TIMEOUT_MS: 5 * TIME.MINUTE,
509
- POLL_INTERVAL_MS: 2e3,
510
- // 5002000ms (75% less API calls)
511
- MIN_IDLE_TIME_MS: 3 * TIME.SECOND,
512
- // 5s3s (faster detection)
513
- MIN_STABILITY_MS: 2 * TIME.SECOND,
514
- // 3s2s (faster stability)
511
+ POLL_INTERVAL_MS: 5e3,
512
+ // 2000ms5000ms (To reduce load)
513
+ MIN_IDLE_TIME_MS: 5 * TIME.SECOND,
514
+ // 3s5s (Less jittery)
515
+ MIN_STABILITY_MS: 5 * TIME.SECOND,
516
+ // 2s5s (More stable)
515
517
  STABLE_POLLS_REQUIRED: 2,
516
- // 3 → 2 (faster completion)
518
+ // 3 → 2 (Faster completion)
517
519
  MAX_POLL_COUNT: 150,
518
- // 600 → 150 (adjusted for 2s interval)
520
+ // 600 → 150 (Adjusted for 2s interval)
519
521
  // Session naming
520
522
  SESSION_TITLE_PREFIX: "Parallel",
521
523
  // Labels for output
@@ -637,7 +639,7 @@ var init_mission_control = __esm({
637
639
  init_limits();
638
640
  MISSION_CONTROL = {
639
641
  DEFAULT_MAX_ITERATIONS: LIMITS.MAX_ITERATIONS,
640
- DEFAULT_COUNTDOWN_SECONDS: 3,
642
+ DEFAULT_COUNTDOWN_SECONDS: 10,
641
643
  STATE_FILE: "loop-state.json",
642
644
  STOP_COMMAND: "/stop",
643
645
  CANCEL_COMMAND: "/cancel",
@@ -18586,7 +18588,7 @@ var ConcurrencyController = class {
18586
18588
  const streak = (this.successStreak.get(key) ?? 0) + 1;
18587
18589
  this.successStreak.set(key, streak);
18588
18590
  this.failureCount.set(key, 0);
18589
- if (streak >= 3) {
18591
+ if (streak >= 5) {
18590
18592
  const currentLimit = this.getConcurrencyLimit(key);
18591
18593
  if (currentLimit < PARALLEL_TASK.MAX_CONCURRENCY) {
18592
18594
  this.setLimit(key, currentLimit + 1);
@@ -18825,9 +18827,9 @@ Use \`get_task_result({ taskId: "task_xxx" })\` to retrieve results.
18825
18827
 
18826
18828
  // src/core/session/session-health.ts
18827
18829
  var sessionHealth = /* @__PURE__ */ new Map();
18828
- var STALE_THRESHOLD_MS = 12e4;
18829
- var HEALTH_CHECK_INTERVAL_MS = 3e4;
18830
- var WARNING_THRESHOLD_MS = 6e4;
18830
+ var STALE_THRESHOLD_MS = 6e5;
18831
+ var HEALTH_CHECK_INTERVAL_MS = 6e4;
18832
+ var WARNING_THRESHOLD_MS = 3e5;
18831
18833
  var healthCheckTimer;
18832
18834
  var client;
18833
18835
  function recordSessionResponse(sessionID) {
@@ -18837,11 +18839,6 @@ function recordSessionResponse(sessionID) {
18837
18839
  health.isStale = false;
18838
18840
  }
18839
18841
  }
18840
- function isSessionStale(sessionID) {
18841
- const health = sessionHealth.get(sessionID);
18842
- if (!health) return false;
18843
- return health.isStale;
18844
- }
18845
18842
  function startHealthCheck(opencodeClient) {
18846
18843
  if (healthCheckTimer) {
18847
18844
  log("[session-health] Health check already running");
@@ -33596,7 +33593,8 @@ var CONFIG = {
33596
33593
  TASK_TTL_MS: PARALLEL_TASK.TTL_MS,
33597
33594
  CLEANUP_DELAY_MS: PARALLEL_TASK.CLEANUP_DELAY_MS,
33598
33595
  MIN_STABILITY_MS: PARALLEL_TASK.MIN_STABILITY_MS,
33599
- POLL_INTERVAL_MS: PARALLEL_TASK.POLL_INTERVAL_MS
33596
+ POLL_INTERVAL_MS: PARALLEL_TASK.POLL_INTERVAL_MS,
33597
+ STABLE_POLLS_REQUIRED: PARALLEL_TASK.STABLE_POLLS_REQUIRED
33600
33598
  };
33601
33599
 
33602
33600
  // src/core/agents/manager/task-poller.ts
@@ -33697,7 +33695,7 @@ var ProgressNotifier = class _ProgressNotifier {
33697
33695
  var progressNotifier = ProgressNotifier.getInstance();
33698
33696
 
33699
33697
  // src/core/agents/manager/task-poller.ts
33700
- var MAX_TASK_DURATION_MS = 6e5;
33698
+ var MAX_TASK_DURATION_MS = 18e5;
33701
33699
  var TaskPoller = class {
33702
33700
  constructor(client2, store, concurrency, notifyParentIfAllComplete, scheduleCleanup, pruneExpiredTasks, onTaskComplete, onTaskError) {
33703
33701
  this.client = client2;
@@ -33709,22 +33707,26 @@ var TaskPoller = class {
33709
33707
  this.onTaskComplete = onTaskComplete;
33710
33708
  this.onTaskError = onTaskError;
33711
33709
  }
33712
- pollingInterval;
33710
+ pollTimeout;
33713
33711
  messageCache = /* @__PURE__ */ new Map();
33714
33712
  start() {
33715
- if (this.pollingInterval) return;
33713
+ if (this.pollTimeout) return;
33716
33714
  log("[task-poller.ts] start() - polling started");
33717
- this.pollingInterval = setInterval(() => this.poll(), CONFIG.POLL_INTERVAL_MS);
33718
- this.pollingInterval.unref();
33715
+ this.scheduleNextPoll();
33719
33716
  }
33720
33717
  stop() {
33721
- if (this.pollingInterval) {
33722
- clearInterval(this.pollingInterval);
33723
- this.pollingInterval = void 0;
33718
+ if (this.pollTimeout) {
33719
+ clearTimeout(this.pollTimeout);
33720
+ this.pollTimeout = void 0;
33724
33721
  }
33725
33722
  }
33726
33723
  isRunning() {
33727
- return !!this.pollingInterval;
33724
+ return !!this.pollTimeout;
33725
+ }
33726
+ scheduleNextPoll() {
33727
+ if (this.pollTimeout) clearTimeout(this.pollTimeout);
33728
+ this.pollTimeout = setTimeout(() => this.poll(), CONFIG.POLL_INTERVAL_MS);
33729
+ this.pollTimeout.unref();
33728
33730
  }
33729
33731
  async poll() {
33730
33732
  this.pruneExpiredTasks();
@@ -33740,11 +33742,6 @@ var TaskPoller = class {
33740
33742
  for (const task of running) {
33741
33743
  try {
33742
33744
  const taskDuration = Date.now() - task.startedAt.getTime();
33743
- if (isSessionStale(task.sessionID)) {
33744
- log(`[task-poller] Task ${task.id} session is stale. Marking as error.`);
33745
- this.onTaskError?.(task.id, new Error("Session became stale (no response from agent)"));
33746
- continue;
33747
- }
33748
33745
  if (taskDuration > MAX_TASK_DURATION_MS) {
33749
33746
  log(`[task-poller] Task ${task.id} exceeded max duration (${MAX_TASK_DURATION_MS}ms). Marking as error.`);
33750
33747
  this.onTaskError?.(task.id, new Error("Task exceeded maximum execution time"));
@@ -33759,11 +33756,11 @@ var TaskPoller = class {
33759
33756
  await this.completeTask(task);
33760
33757
  continue;
33761
33758
  }
33762
- await this.updateTaskProgress(task);
33759
+ await this.updateTaskProgress(task, sessionStatus);
33763
33760
  const elapsed = Date.now() - task.startedAt.getTime();
33764
- if (elapsed >= CONFIG.MIN_STABILITY_MS && task.stablePolls && task.stablePolls >= 3) {
33761
+ if (elapsed >= CONFIG.MIN_STABILITY_MS && task.stablePolls && task.stablePolls >= CONFIG.STABLE_POLLS_REQUIRED) {
33765
33762
  if (task.hasStartedOutputting || await this.validateSessionHasOutput(task.sessionID, task)) {
33766
- log(`Task ${task.id} stable for 3 polls, completing...`);
33763
+ log(`Task ${task.id} stable for ${task.stablePolls} polls, completing...`);
33767
33764
  await this.completeTask(task);
33768
33765
  }
33769
33766
  }
@@ -33774,6 +33771,12 @@ var TaskPoller = class {
33774
33771
  progressNotifier.update();
33775
33772
  } catch (error92) {
33776
33773
  log("Polling error:", error92);
33774
+ } finally {
33775
+ if (this.store.getRunning().length > 0) {
33776
+ this.scheduleNextPoll();
33777
+ } else {
33778
+ this.stop();
33779
+ }
33777
33780
  }
33778
33781
  }
33779
33782
  async validateSessionHasOutput(sessionID, task) {
@@ -33812,12 +33815,15 @@ var TaskPoller = class {
33812
33815
  log(`Completed ${task.id} (${duration5})`);
33813
33816
  progressNotifier.update();
33814
33817
  }
33815
- async updateTaskProgress(task) {
33818
+ async updateTaskProgress(task, sessionStatus) {
33816
33819
  try {
33817
33820
  const cached3 = this.messageCache.get(task.sessionID);
33818
- const statusResult = await this.client.session.status();
33819
- const sessionInfo = statusResult.data?.[task.sessionID];
33820
- const currentMsgCount = sessionInfo?.messageCount ?? 0;
33821
+ let currentMsgCount = sessionStatus?.messageCount;
33822
+ if (currentMsgCount === void 0) {
33823
+ const statusResult = await this.client.session.status();
33824
+ const sessionInfo = statusResult.data?.[task.sessionID];
33825
+ currentMsgCount = sessionInfo?.messageCount ?? 0;
33826
+ }
33821
33827
  if (cached3 && cached3.count === currentMsgCount) {
33822
33828
  task.stablePolls = (task.stablePolls ?? 0) + 1;
33823
33829
  return;
@@ -33977,7 +33983,7 @@ init_shared();
33977
33983
 
33978
33984
  // src/core/loop/continuation-lock.ts
33979
33985
  var locks = /* @__PURE__ */ new Map();
33980
- var LOCK_TIMEOUT_MS = 3e4;
33986
+ var LOCK_TIMEOUT_MS = 12e4;
33981
33987
  function tryAcquireContinuationLock(sessionID, source) {
33982
33988
  const now = Date.now();
33983
33989
  const existing = locks.get(sessionID);
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export declare const MISSION_CONTROL: {
5
5
  readonly DEFAULT_MAX_ITERATIONS: 10000;
6
- readonly DEFAULT_COUNTDOWN_SECONDS: 3;
6
+ readonly DEFAULT_COUNTDOWN_SECONDS: 10;
7
7
  readonly STATE_FILE: "loop-state.json";
8
8
  readonly STOP_COMMAND: "/stop";
9
9
  readonly CANCEL_COMMAND: "/cancel";
@@ -12,7 +12,7 @@ export declare const MISSION_CONTROL: {
12
12
  /** @deprecated Use MISSION_CONTROL instead */
13
13
  export declare const MISSION: {
14
14
  readonly DEFAULT_MAX_ITERATIONS: 10000;
15
- readonly DEFAULT_COUNTDOWN_SECONDS: 3;
15
+ readonly DEFAULT_COUNTDOWN_SECONDS: 10;
16
16
  readonly STATE_FILE: "loop-state.json";
17
17
  readonly STOP_COMMAND: "/stop";
18
18
  readonly CANCEL_COMMAND: "/cancel";
@@ -27,10 +27,10 @@ export declare const PARALLEL_TASK: {
27
27
  * Worker and Reviewer are terminal nodes by design.
28
28
  */
29
29
  readonly TERMINAL_DEPTH: 2;
30
- readonly DEFAULT_CONCURRENCY: 10;
31
- readonly MAX_CONCURRENCY: 50;
30
+ readonly DEFAULT_CONCURRENCY: 3;
31
+ readonly MAX_CONCURRENCY: 5;
32
32
  readonly SYNC_TIMEOUT_MS: number;
33
- readonly POLL_INTERVAL_MS: 2000;
33
+ readonly POLL_INTERVAL_MS: 5000;
34
34
  readonly MIN_IDLE_TIME_MS: number;
35
35
  readonly MIN_STABILITY_MS: number;
36
36
  readonly STABLE_POLLS_REQUIRED: 2;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "opencode-orchestrator",
3
3
  "displayName": "OpenCode Orchestrator",
4
4
  "description": "Distributed Cognitive Architecture for OpenCode. Turns simple prompts into specialized multi-agent workflows (Planner, Coder, Reviewer).",
5
- "version": "1.2.15",
5
+ "version": "1.2.17",
6
6
  "author": "agnusdei1207",
7
7
  "license": "MIT",
8
8
  "repository": {