opencara 0.23.13 → 0.23.15

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 (2) hide show
  1. package/dist/index.js +64 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -132,7 +132,7 @@ function parseTriggerSection(raw, defaults) {
132
132
  }
133
133
  return result;
134
134
  }
135
- var DEFAULT_MODEL_DIVERSITY_GRACE_MS = 3e4;
135
+ var DEFAULT_MODEL_DIVERSITY_GRACE_MS = 3e5;
136
136
  function parseDurationSeconds(value, defaultMs) {
137
137
  if (typeof value === "number")
138
138
  return value === 0 ? 0 : clamp(value, 0, 300) * 1e3;
@@ -4825,9 +4825,11 @@ function concatUint8Arrays(chunks, totalLength) {
4825
4825
  return result;
4826
4826
  }
4827
4827
  var MAX_DIFF_FETCH_ATTEMPTS = 3;
4828
+ var MAX_TASK_ERROR_ATTEMPTS = 3;
4828
4829
  var WEIGHT_PENALTY_FACTOR = 0.5;
4829
4830
  var MIN_DISPATCH_WEIGHT = 0.1;
4830
4831
  var WEIGHT_RECOVERY = 0.25;
4832
+ var WEIGHT_RECOVERY_DURATION_MS = 30 * 60 * 1e3;
4831
4833
  async function pollLoop(client, agentId, reviewDeps, consumptionDeps, agentInfo, logger, agentSession, options) {
4832
4834
  const {
4833
4835
  pollIntervalMs,
@@ -5317,6 +5319,7 @@ async function handleTask(client, agentId, task, reviewDeps, consumptionDeps, ag
5317
5319
  logError(` ${icons.error} Error on task ${task_id}: ${err.message}`);
5318
5320
  await safeError(client, task_id, agentId, err.message, logger);
5319
5321
  }
5322
+ return { toolFailed: true };
5320
5323
  } finally {
5321
5324
  if (taskCheckoutPath && taskBareRepoPath) {
5322
5325
  if (cleanupTracker) {
@@ -5698,7 +5701,7 @@ function sleep2(ms, signal) {
5698
5701
  async function startAgent(agentId, platformUrl, agentInfo, reviewDeps, consumptionDeps, options) {
5699
5702
  const client = new ApiClient(platformUrl, {
5700
5703
  authToken: options?.authToken,
5701
- cliVersion: "0.23.13",
5704
+ cliVersion: "0.23.15",
5702
5705
  versionOverride: options?.versionOverride,
5703
5706
  onTokenRefresh: options?.onTokenRefresh
5704
5707
  });
@@ -5873,13 +5876,31 @@ async function batchPollLoop(client, agentStates, options) {
5873
5876
  const response = await client.post("/api/tasks/poll/batch", request);
5874
5877
  consecutiveAuthErrors = 0;
5875
5878
  consecutiveErrors = 0;
5879
+ const now = Date.now();
5880
+ for (const s of availableStates) {
5881
+ if (s.weight < 1) {
5882
+ const elapsed = now - s.lastWeightUpdateAt;
5883
+ const recovered = Math.min(1, s.weight + elapsed / WEIGHT_RECOVERY_DURATION_MS);
5884
+ if (recovered > s.weight) {
5885
+ s.weight = recovered;
5886
+ if (s.weight >= MIN_DISPATCH_WEIGHT && s.pausedLogged) {
5887
+ s.logger.log(
5888
+ `${icons.info} Agent resumed (weight ${s.weight.toFixed(2)} \u2265 ${MIN_DISPATCH_WEIGHT})`
5889
+ );
5890
+ s.pausedLogged = false;
5891
+ }
5892
+ }
5893
+ }
5894
+ s.lastWeightUpdateAt = now;
5895
+ }
5876
5896
  const eligibleStates = availableStates.filter((s) => s.weight >= MIN_DISPATCH_WEIGHT);
5877
5897
  const dispatchOrder = eligibleStates.map((s) => ({ state: s, score: s.weight * Math.random() })).sort((a, b) => b.score - a.score).map((e) => e.state);
5878
5898
  for (const s of availableStates) {
5879
- if (s.weight < MIN_DISPATCH_WEIGHT) {
5899
+ if (s.weight < MIN_DISPATCH_WEIGHT && !s.pausedLogged) {
5880
5900
  s.logger.logWarn(
5881
- `${icons.warn} Agent paused (weight ${s.weight.toFixed(2)} < ${MIN_DISPATCH_WEIGHT})`
5901
+ `${icons.warn} Agent paused (weight ${s.weight.toFixed(2)} < ${MIN_DISPATCH_WEIGHT}), recovering over ${WEIGHT_RECOVERY_DURATION_MS / 6e4}m`
5882
5902
  );
5903
+ s.pausedLogged = true;
5883
5904
  }
5884
5905
  }
5885
5906
  for (const state of dispatchOrder) {
@@ -5895,7 +5916,9 @@ async function batchPollLoop(client, agentStates, options) {
5895
5916
  accessibleRepos,
5896
5917
  (msg) => state.logger.logWarn(`${icons.warn} ${msg}`)
5897
5918
  );
5898
- const task = eligible[0];
5919
+ const task = eligible.find(
5920
+ (t) => (state.taskErrorCounts.get(t.task_id) ?? 0) < MAX_TASK_ERROR_ATTEMPTS
5921
+ );
5899
5922
  if (!task) continue;
5900
5923
  busyAgents.add(state);
5901
5924
  const p = (async () => {
@@ -5928,16 +5951,45 @@ async function batchPollLoop(client, agentStates, options) {
5928
5951
  );
5929
5952
  }
5930
5953
  state.weight = Math.max(0, state.weight * WEIGHT_PENALTY_FACTOR);
5954
+ state.lastWeightUpdateAt = Date.now();
5931
5955
  state.logger.logWarn(
5932
5956
  `${icons.warn} Weight reduced to ${state.weight.toFixed(2)} after diff fetch failure`
5933
5957
  );
5958
+ } else if (result.toolFailed) {
5959
+ const errCount = (state.taskErrorCounts.get(task.task_id) ?? 0) + 1;
5960
+ state.taskErrorCounts.set(task.task_id, errCount);
5961
+ if (errCount >= MAX_TASK_ERROR_ATTEMPTS) {
5962
+ state.logger.logWarn(
5963
+ `${icons.warn} Giving up on task ${task.task_id.slice(0, 8)}\u2026 after ${errCount} tool failures`
5964
+ );
5965
+ }
5966
+ state.weight = Math.max(0, state.weight * WEIGHT_PENALTY_FACTOR);
5967
+ state.lastWeightUpdateAt = Date.now();
5968
+ state.logger.logWarn(
5969
+ `${icons.warn} Weight reduced to ${state.weight.toFixed(2)} after tool error`
5970
+ );
5934
5971
  } else {
5935
5972
  state.weight = Math.min(1, state.weight + WEIGHT_RECOVERY);
5973
+ state.lastWeightUpdateAt = Date.now();
5974
+ if (state.weight >= MIN_DISPATCH_WEIGHT && state.pausedLogged) {
5975
+ state.logger.log(
5976
+ `${icons.info} Agent resumed (weight ${state.weight.toFixed(2)} \u2265 ${MIN_DISPATCH_WEIGHT})`
5977
+ );
5978
+ state.pausedLogged = false;
5979
+ }
5936
5980
  }
5937
5981
  } catch (err) {
5938
5982
  logError(`${icons.error} Task handler failed: ${err.message}`);
5939
5983
  consecutiveErrors++;
5984
+ const errCount = (state.taskErrorCounts.get(task.task_id) ?? 0) + 1;
5985
+ state.taskErrorCounts.set(task.task_id, errCount);
5986
+ if (errCount >= MAX_TASK_ERROR_ATTEMPTS) {
5987
+ state.logger.logWarn(
5988
+ `${icons.warn} Giving up on task ${task.task_id.slice(0, 8)}\u2026 after ${errCount} failures`
5989
+ );
5990
+ }
5940
5991
  state.weight = Math.max(0, state.weight * WEIGHT_PENALTY_FACTOR);
5992
+ state.lastWeightUpdateAt = Date.now();
5941
5993
  state.logger.logWarn(
5942
5994
  `${icons.warn} Weight reduced to ${state.weight.toFixed(2)} after task error`
5943
5995
  );
@@ -6014,7 +6066,7 @@ async function startBatchAgents(config, agents, pollIntervalMs, oauthToken, opti
6014
6066
  const { versionOverride, verbose, instancesOverride, agentOwner, userOrgs } = options;
6015
6067
  const client = new ApiClient(config.platformUrl, {
6016
6068
  authToken: oauthToken,
6017
- cliVersion: "0.23.13",
6069
+ cliVersion: "0.23.15",
6018
6070
  versionOverride,
6019
6071
  onTokenRefresh: () => getValidToken(config.platformUrl, { configPath: config.authFile })
6020
6072
  });
@@ -6094,7 +6146,10 @@ async function startBatchAgents(config, agents, pollIntervalMs, oauthToken, opti
6094
6146
  cleanupTracker,
6095
6147
  verbose,
6096
6148
  diffFailCounts: /* @__PURE__ */ new Map(),
6097
- weight: 1
6149
+ taskErrorCounts: /* @__PURE__ */ new Map(),
6150
+ weight: 1,
6151
+ lastWeightUpdateAt: Date.now(),
6152
+ pausedLogged: false
6098
6153
  });
6099
6154
  }
6100
6155
  }
@@ -6360,7 +6415,7 @@ agentCommand.command("start").description("Start agents in polling mode").option
6360
6415
  }
6361
6416
  config = loadConfig();
6362
6417
  }
6363
- console.log(formatVersionBanner("0.23.13", "791981e"));
6418
+ console.log(formatVersionBanner("0.23.15", "c8030a0"));
6364
6419
  if (config.agents && config.agents.length > 0) {
6365
6420
  const toolEntries = config.agents.map((a) => ({
6366
6421
  tool: a.tool,
@@ -7182,7 +7237,7 @@ var statusCommand = new Command4("status").description("Show agent config, conne
7182
7237
  });
7183
7238
 
7184
7239
  // src/index.ts
7185
- var program = new Command5().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version(`${"0.23.13"} (${"791981e"})`);
7240
+ var program = new Command5().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version(`${"0.23.15"} (${"c8030a0"})`);
7186
7241
  program.addCommand(agentCommand);
7187
7242
  program.addCommand(authCommand());
7188
7243
  program.addCommand(dedupCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencara",
3
- "version": "0.23.13",
3
+ "version": "0.23.15",
4
4
  "description": "Distributed AI code review agent — poll, review, and submit PR reviews using your own AI tools",
5
5
  "type": "module",
6
6
  "license": "MIT",