opencara 0.15.1 → 0.15.3

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 +63 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -869,6 +869,23 @@ function buildSystemPrompt(owner, repo, mode = "full") {
869
869
  const template = mode === "compact" ? COMPACT_SYSTEM_PROMPT_TEMPLATE : FULL_SYSTEM_PROMPT_TEMPLATE;
870
870
  return template.replace("{owner}", owner).replace("{repo}", repo);
871
871
  }
872
+ var VERDICT_EMOJI = {
873
+ approve: "\u2705",
874
+ request_changes: "\u274C",
875
+ comment: "\u{1F4AC}"
876
+ };
877
+ function buildMetadataHeader(verdict, meta) {
878
+ if (!meta) return "";
879
+ const emoji = VERDICT_EMOJI[verdict] ?? "";
880
+ const lines = [`**Reviewer**: \`${meta.model}/${meta.tool}\``];
881
+ if (meta.githubUsername) {
882
+ lines.push(
883
+ `**Contributors**: [@${meta.githubUsername}](https://github.com/${meta.githubUsername})`
884
+ );
885
+ }
886
+ lines.push(`**Verdict**: ${emoji} ${verdict}`);
887
+ return lines.join("\n") + "\n\n";
888
+ }
872
889
  function buildUserMessage(prompt, diffContent, contextBlock) {
873
890
  const parts = [prompt];
874
891
  if (contextBlock) {
@@ -963,6 +980,22 @@ var InputTooLargeError = class extends Error {
963
980
  this.name = "InputTooLargeError";
964
981
  }
965
982
  };
983
+ function buildSummaryMetadataHeader(verdict, meta) {
984
+ if (!meta) return "";
985
+ const emoji = VERDICT_EMOJI[verdict] ?? "";
986
+ const reviewersList = meta.reviewerModels.map((r) => `\`${r}\``).join(", ");
987
+ const lines = [
988
+ `**Reviewers**: ${reviewersList}`,
989
+ `**Synthesizer**: \`${meta.model}/${meta.tool}\``
990
+ ];
991
+ if (meta.githubUsername) {
992
+ lines.push(
993
+ `**Contributors**: [@${meta.githubUsername}](https://github.com/${meta.githubUsername})`
994
+ );
995
+ }
996
+ lines.push(`**Verdict**: ${emoji} ${verdict}`);
997
+ return lines.join("\n") + "\n\n";
998
+ }
966
999
  function buildSummarySystemPrompt(owner, repo, reviewCount) {
967
1000
  return `You are a senior code reviewer and lead synthesizer for the ${owner}/${repo} repository.
968
1001
 
@@ -1060,6 +1093,7 @@ ${userMessage}`;
1060
1093
  void 0,
1061
1094
  deps.codebaseDir ?? void 0
1062
1095
  );
1096
+ const { verdict, review } = extractVerdict(result.stdout);
1063
1097
  const inputTokens = result.tokensParsed ? 0 : estimateTokens(fullPrompt);
1064
1098
  const detail = result.tokenDetail;
1065
1099
  const tokenDetail = result.tokensParsed ? detail : {
@@ -1069,7 +1103,8 @@ ${userMessage}`;
1069
1103
  parsed: false
1070
1104
  };
1071
1105
  return {
1072
- summary: result.stdout,
1106
+ summary: review,
1107
+ verdict,
1073
1108
  tokensUsed: result.tokensUsed + inputTokens,
1074
1109
  tokensEstimated: !result.tokensParsed,
1075
1110
  tokenDetail
@@ -1692,13 +1727,6 @@ function concatUint8Arrays(chunks, totalLength) {
1692
1727
  return result;
1693
1728
  }
1694
1729
  var MAX_DIFF_FETCH_ATTEMPTS = 3;
1695
- function appendContributorAttribution(text, githubUsername) {
1696
- if (!githubUsername) return text;
1697
- return `${text}
1698
-
1699
- ---
1700
- Contributed by [@${githubUsername}](https://github.com/${githubUsername})`;
1701
- }
1702
1730
  async function pollLoop(client, agentId, reviewDeps, consumptionDeps, agentInfo, logger, agentSession, options) {
1703
1731
  const {
1704
1732
  pollIntervalMs,
@@ -1926,6 +1954,7 @@ async function handleTask(client, agentId, task, reviewDeps, consumptionDeps, ag
1926
1954
  taskReviewDeps,
1927
1955
  consumptionDeps,
1928
1956
  logger,
1957
+ agentInfo,
1929
1958
  routerRelay,
1930
1959
  signal,
1931
1960
  contextBlock,
@@ -1945,6 +1974,7 @@ async function handleTask(client, agentId, task, reviewDeps, consumptionDeps, ag
1945
1974
  taskReviewDeps,
1946
1975
  consumptionDeps,
1947
1976
  logger,
1977
+ agentInfo,
1948
1978
  routerRelay,
1949
1979
  signal,
1950
1980
  contextBlock,
@@ -1998,7 +2028,7 @@ async function safeError(client, taskId, agentId, error, logger) {
1998
2028
  );
1999
2029
  }
2000
2030
  }
2001
- async function executeReviewTask(client, agentId, taskId, owner, repo, prNumber, diffContent, prompt, timeoutSeconds, reviewDeps, consumptionDeps, logger, routerRelay, signal, contextBlock, githubUsername) {
2031
+ async function executeReviewTask(client, agentId, taskId, owner, repo, prNumber, diffContent, prompt, timeoutSeconds, reviewDeps, consumptionDeps, logger, agentInfo, routerRelay, signal, contextBlock, githubUsername) {
2002
2032
  if (consumptionDeps.usageLimits?.maxTokensPerReview != null && consumptionDeps.usageTracker) {
2003
2033
  const estimatedInput = estimateTokens(diffContent + prompt + (contextBlock ?? ""));
2004
2034
  const perReviewCheck = consumptionDeps.usageTracker.checkPerReviewLimit(
@@ -2065,7 +2095,13 @@ async function executeReviewTask(client, agentId, taskId, owner, repo, prNumber,
2065
2095
  estimated: result.tokensEstimated
2066
2096
  };
2067
2097
  }
2068
- const sanitizedReview = appendContributorAttribution(sanitizeTokens(reviewText), githubUsername);
2098
+ const reviewMeta = {
2099
+ model: agentInfo.model,
2100
+ tool: agentInfo.tool,
2101
+ githubUsername
2102
+ };
2103
+ const headerReview = buildMetadataHeader(verdict, reviewMeta);
2104
+ const sanitizedReview = sanitizeTokens(headerReview + reviewText);
2069
2105
  await withRetry(
2070
2106
  () => client.post(`/api/tasks/${taskId}/result`, {
2071
2107
  agent_id: agentId,
@@ -2088,7 +2124,8 @@ async function executeReviewTask(client, agentId, taskId, owner, repo, prNumber,
2088
2124
  logger.log(` ${icons.success} Review submitted (${tokensUsed.toLocaleString()} tokens)`);
2089
2125
  logger.log(formatPostReviewStats(consumptionDeps.session));
2090
2126
  }
2091
- async function executeSummaryTask(client, agentId, taskId, owner, repo, prNumber, diffContent, prompt, timeoutSeconds, reviews, reviewDeps, consumptionDeps, logger, routerRelay, signal, contextBlock, githubUsername) {
2127
+ async function executeSummaryTask(client, agentId, taskId, owner, repo, prNumber, diffContent, prompt, timeoutSeconds, reviews, reviewDeps, consumptionDeps, logger, agentInfo, routerRelay, signal, contextBlock, githubUsername) {
2128
+ const meta = { model: agentInfo.model, tool: agentInfo.tool, githubUsername };
2092
2129
  if (reviews.length === 0) {
2093
2130
  let reviewText;
2094
2131
  let verdict;
@@ -2146,10 +2183,8 @@ async function executeSummaryTask(client, agentId, taskId, owner, repo, prNumber
2146
2183
  estimated: result.tokensEstimated
2147
2184
  };
2148
2185
  }
2149
- const sanitizedReview = appendContributorAttribution(
2150
- sanitizeTokens(reviewText),
2151
- githubUsername
2152
- );
2186
+ const headerSingle = buildMetadataHeader(verdict ?? "comment", meta);
2187
+ const sanitizedReview = sanitizeTokens(headerSingle + reviewText);
2153
2188
  await withRetry(
2154
2189
  () => client.post(`/api/tasks/${taskId}/result`, {
2155
2190
  agent_id: agentId,
@@ -2183,6 +2218,7 @@ async function executeSummaryTask(client, agentId, taskId, owner, repo, prNumber
2183
2218
  verdict: r.verdict
2184
2219
  }));
2185
2220
  let summaryText;
2221
+ let summaryVerdict;
2186
2222
  let tokensUsed;
2187
2223
  let usageOpts;
2188
2224
  if (routerRelay) {
@@ -2201,7 +2237,9 @@ async function executeSummaryTask(client, agentId, taskId, owner, repo, prNumber
2201
2237
  fullPrompt,
2202
2238
  timeoutSeconds
2203
2239
  );
2204
- summaryText = response;
2240
+ const parsed = extractVerdict(response);
2241
+ summaryText = parsed.review;
2242
+ summaryVerdict = parsed.verdict;
2205
2243
  tokensUsed = estimateTokens(fullPrompt) + estimateTokens(response);
2206
2244
  usageOpts = {
2207
2245
  inputTokens: estimateTokens(fullPrompt),
@@ -2226,6 +2264,7 @@ async function executeSummaryTask(client, agentId, taskId, owner, repo, prNumber
2226
2264
  reviewDeps
2227
2265
  );
2228
2266
  summaryText = result.summary;
2267
+ summaryVerdict = result.verdict;
2229
2268
  tokensUsed = result.tokensUsed;
2230
2269
  usageOpts = {
2231
2270
  inputTokens: result.tokenDetail.input,
@@ -2234,15 +2273,18 @@ async function executeSummaryTask(client, agentId, taskId, owner, repo, prNumber
2234
2273
  estimated: result.tokensEstimated
2235
2274
  };
2236
2275
  }
2237
- const sanitizedSummary = appendContributorAttribution(
2238
- sanitizeTokens(summaryText),
2239
- githubUsername
2240
- );
2276
+ const summaryMeta = {
2277
+ ...meta,
2278
+ reviewerModels: summaryReviews.map((r) => `${r.model}/${r.tool}`)
2279
+ };
2280
+ const headerSummary = buildSummaryMetadataHeader(summaryVerdict, summaryMeta);
2281
+ const sanitizedSummary = sanitizeTokens(headerSummary + summaryText);
2241
2282
  await withRetry(
2242
2283
  () => client.post(`/api/tasks/${taskId}/result`, {
2243
2284
  agent_id: agentId,
2244
2285
  type: "summary",
2245
2286
  review_text: sanitizedSummary,
2287
+ verdict: summaryVerdict,
2246
2288
  tokens_used: tokensUsed
2247
2289
  }),
2248
2290
  { maxAttempts: 3 },
@@ -2529,7 +2571,7 @@ agentCommand.command("start").description("Start agents in polling mode").option
2529
2571
  });
2530
2572
 
2531
2573
  // src/index.ts
2532
- var program = new Command2().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version("0.15.1");
2574
+ var program = new Command2().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version("0.15.3");
2533
2575
  program.addCommand(agentCommand);
2534
2576
  program.action(() => {
2535
2577
  startAgentRouter();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencara",
3
- "version": "0.15.1",
3
+ "version": "0.15.3",
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",