opencara 0.7.1 → 0.8.0
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.js +135 -55
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14,9 +14,10 @@ import * as os from "os";
|
|
|
14
14
|
import { parse, stringify } from "yaml";
|
|
15
15
|
var DEFAULT_PLATFORM_URL = "https://api.opencara.dev";
|
|
16
16
|
var CONFIG_DIR = path.join(os.homedir(), ".opencara");
|
|
17
|
-
var CONFIG_FILE = path.join(CONFIG_DIR, "config.yml");
|
|
17
|
+
var CONFIG_FILE = process.env.OPENCARA_CONFIG && process.env.OPENCARA_CONFIG.trim() ? path.resolve(process.env.OPENCARA_CONFIG) : path.join(CONFIG_DIR, "config.yml");
|
|
18
18
|
function ensureConfigDir() {
|
|
19
|
-
|
|
19
|
+
const dir = path.dirname(CONFIG_FILE);
|
|
20
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
20
21
|
}
|
|
21
22
|
var DEFAULT_MAX_DIFF_SIZE_KB = 100;
|
|
22
23
|
function parseLimits(data) {
|
|
@@ -96,6 +97,7 @@ function parseAnonymousAgents(data) {
|
|
|
96
97
|
model: obj.model,
|
|
97
98
|
tool: obj.tool
|
|
98
99
|
};
|
|
100
|
+
if (typeof obj.name === "string") anon.name = obj.name;
|
|
99
101
|
if (obj.repo_config && typeof obj.repo_config === "object") {
|
|
100
102
|
const rc = obj.repo_config;
|
|
101
103
|
if (typeof rc.mode === "string" && VALID_REPO_MODES.includes(rc.mode)) {
|
|
@@ -127,6 +129,7 @@ function parseAgents(data) {
|
|
|
127
129
|
continue;
|
|
128
130
|
}
|
|
129
131
|
const agent = { model: obj.model, tool: obj.tool };
|
|
132
|
+
if (typeof obj.name === "string") agent.name = obj.name;
|
|
130
133
|
if (typeof obj.command === "string") agent.command = obj.command;
|
|
131
134
|
const agentLimits = parseLimits(obj);
|
|
132
135
|
if (agentLimits) agent.limits = agentLimits;
|
|
@@ -192,6 +195,9 @@ function saveConfig(config) {
|
|
|
192
195
|
model: a.model,
|
|
193
196
|
tool: a.tool
|
|
194
197
|
};
|
|
198
|
+
if (a.name) {
|
|
199
|
+
entry.name = a.name;
|
|
200
|
+
}
|
|
195
201
|
if (a.repoConfig) {
|
|
196
202
|
entry.repo_config = a.repoConfig;
|
|
197
203
|
}
|
|
@@ -293,17 +299,17 @@ function calculateDelay(attempt, options = DEFAULT_RECONNECT_OPTIONS) {
|
|
|
293
299
|
return base;
|
|
294
300
|
}
|
|
295
301
|
function sleep(ms) {
|
|
296
|
-
return new Promise((
|
|
302
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
297
303
|
}
|
|
298
304
|
|
|
299
305
|
// src/commands/login.ts
|
|
300
306
|
function promptYesNo(question) {
|
|
301
307
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
302
|
-
return new Promise((
|
|
308
|
+
return new Promise((resolve2) => {
|
|
303
309
|
rl.question(question, (answer) => {
|
|
304
310
|
rl.close();
|
|
305
311
|
const normalized = answer.trim().toLowerCase();
|
|
306
|
-
|
|
312
|
+
resolve2(normalized === "" || normalized === "y" || normalized === "yes");
|
|
307
313
|
});
|
|
308
314
|
});
|
|
309
315
|
}
|
|
@@ -428,24 +434,56 @@ var DEFAULT_REGISTRY = {
|
|
|
428
434
|
}
|
|
429
435
|
],
|
|
430
436
|
models: [
|
|
431
|
-
{
|
|
437
|
+
{
|
|
438
|
+
name: "claude-opus-4-6",
|
|
439
|
+
displayName: "Claude Opus 4.6",
|
|
440
|
+
tools: ["claude"],
|
|
441
|
+
defaultReputation: 0.8
|
|
442
|
+
},
|
|
432
443
|
{
|
|
433
444
|
name: "claude-opus-4-6[1m]",
|
|
434
445
|
displayName: "Claude Opus 4.6 (1M context)",
|
|
435
|
-
tools: ["claude"]
|
|
446
|
+
tools: ["claude"],
|
|
447
|
+
defaultReputation: 0.8
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
name: "claude-sonnet-4-6",
|
|
451
|
+
displayName: "Claude Sonnet 4.6",
|
|
452
|
+
tools: ["claude"],
|
|
453
|
+
defaultReputation: 0.7
|
|
436
454
|
},
|
|
437
|
-
{ name: "claude-sonnet-4-6", displayName: "Claude Sonnet 4.6", tools: ["claude"] },
|
|
438
455
|
{
|
|
439
456
|
name: "claude-sonnet-4-6[1m]",
|
|
440
457
|
displayName: "Claude Sonnet 4.6 (1M context)",
|
|
441
|
-
tools: ["claude"]
|
|
458
|
+
tools: ["claude"],
|
|
459
|
+
defaultReputation: 0.7
|
|
442
460
|
},
|
|
443
|
-
{
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
461
|
+
{
|
|
462
|
+
name: "gpt-5-codex",
|
|
463
|
+
displayName: "GPT-5 Codex",
|
|
464
|
+
tools: ["codex"],
|
|
465
|
+
defaultReputation: 0.7
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: "gemini-2.5-pro",
|
|
469
|
+
displayName: "Gemini 2.5 Pro",
|
|
470
|
+
tools: ["gemini"],
|
|
471
|
+
defaultReputation: 0.7
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
name: "qwen3.5-plus",
|
|
475
|
+
displayName: "Qwen 3.5 Plus",
|
|
476
|
+
tools: ["qwen"],
|
|
477
|
+
defaultReputation: 0.6
|
|
478
|
+
},
|
|
479
|
+
{ name: "glm-5", displayName: "GLM-5", tools: ["qwen"], defaultReputation: 0.5 },
|
|
480
|
+
{ name: "kimi-k2.5", displayName: "Kimi K2.5", tools: ["qwen"], defaultReputation: 0.5 },
|
|
481
|
+
{
|
|
482
|
+
name: "minimax-m2.5",
|
|
483
|
+
displayName: "Minimax M2.5",
|
|
484
|
+
tools: ["qwen"],
|
|
485
|
+
defaultReputation: 0.5
|
|
486
|
+
}
|
|
449
487
|
]
|
|
450
488
|
};
|
|
451
489
|
|
|
@@ -554,7 +592,7 @@ function executeTool(commandTemplate, prompt, timeoutMs, signal, vars) {
|
|
|
554
592
|
const promptViaArg = commandTemplate.includes("${PROMPT}");
|
|
555
593
|
const allVars = { ...vars, PROMPT: prompt };
|
|
556
594
|
const { command, args } = parseCommandTemplate(commandTemplate, allVars);
|
|
557
|
-
return new Promise((
|
|
595
|
+
return new Promise((resolve2, reject) => {
|
|
558
596
|
if (signal?.aborted) {
|
|
559
597
|
reject(new ToolTimeoutError("Tool execution aborted"));
|
|
560
598
|
return;
|
|
@@ -626,7 +664,7 @@ function executeTool(commandTemplate, prompt, timeoutMs, signal, vars) {
|
|
|
626
664
|
console.warn(`Tool stderr: ${stderr.slice(0, MAX_STDERR_LENGTH)}`);
|
|
627
665
|
}
|
|
628
666
|
const usage2 = parseTokenUsage(stdout, stderr);
|
|
629
|
-
|
|
667
|
+
resolve2({ stdout, stderr, tokensUsed: usage2.tokens, tokensParsed: usage2.parsed });
|
|
630
668
|
return;
|
|
631
669
|
}
|
|
632
670
|
const errMsg = stderr ? `Tool "${command}" failed (exit code ${code}): ${stderr.slice(0, MAX_STDERR_LENGTH)}` : `Tool "${command}" failed with exit code ${code}`;
|
|
@@ -634,7 +672,7 @@ function executeTool(commandTemplate, prompt, timeoutMs, signal, vars) {
|
|
|
634
672
|
return;
|
|
635
673
|
}
|
|
636
674
|
const usage = parseTokenUsage(stdout, stderr);
|
|
637
|
-
|
|
675
|
+
resolve2({ stdout, stderr, tokensUsed: usage.tokens, tokensParsed: usage.parsed });
|
|
638
676
|
});
|
|
639
677
|
});
|
|
640
678
|
}
|
|
@@ -884,6 +922,7 @@ function formatTable(agents, trustLabels) {
|
|
|
884
922
|
}
|
|
885
923
|
const header = [
|
|
886
924
|
"ID".padEnd(38),
|
|
925
|
+
"Name".padEnd(20),
|
|
887
926
|
"Model".padEnd(22),
|
|
888
927
|
"Tool".padEnd(16),
|
|
889
928
|
"Status".padEnd(10),
|
|
@@ -892,8 +931,16 @@ function formatTable(agents, trustLabels) {
|
|
|
892
931
|
console.log(header);
|
|
893
932
|
for (const a of agents) {
|
|
894
933
|
const trust = trustLabels?.get(a.id) ?? "--";
|
|
934
|
+
const name = a.displayName ?? "--";
|
|
895
935
|
console.log(
|
|
896
|
-
[
|
|
936
|
+
[
|
|
937
|
+
a.id.padEnd(38),
|
|
938
|
+
name.padEnd(20),
|
|
939
|
+
a.model.padEnd(22),
|
|
940
|
+
a.tool.padEnd(16),
|
|
941
|
+
a.status.padEnd(10),
|
|
942
|
+
trust
|
|
943
|
+
].join("")
|
|
897
944
|
);
|
|
898
945
|
}
|
|
899
946
|
}
|
|
@@ -908,6 +955,10 @@ function startAgent(agentId, platformUrl, apiKey, reviewDeps, consumptionDeps, o
|
|
|
908
955
|
const verbose = options?.verbose ?? false;
|
|
909
956
|
const stabilityThreshold = options?.stabilityThresholdMs ?? CONNECTION_STABILITY_THRESHOLD_MS;
|
|
910
957
|
const repoConfig = options?.repoConfig;
|
|
958
|
+
const displayName = options?.displayName;
|
|
959
|
+
const prefix = options?.label ? `[${options.label}]` : "";
|
|
960
|
+
const log = (...args) => console.log(...prefix ? [prefix, ...args] : args);
|
|
961
|
+
const logError = (...args) => console.error(...prefix ? [prefix, ...args] : args);
|
|
911
962
|
let attempt = 0;
|
|
912
963
|
let intentionalClose = false;
|
|
913
964
|
let heartbeatTimer = null;
|
|
@@ -939,7 +990,7 @@ function startAgent(agentId, platformUrl, apiKey, reviewDeps, consumptionDeps, o
|
|
|
939
990
|
clearStabilityTimer();
|
|
940
991
|
clearWsPingTimer();
|
|
941
992
|
if (currentWs) currentWs.close();
|
|
942
|
-
|
|
993
|
+
log("Disconnected.");
|
|
943
994
|
process.exit(0);
|
|
944
995
|
}
|
|
945
996
|
process.once("SIGINT", shutdown);
|
|
@@ -951,13 +1002,13 @@ function startAgent(agentId, platformUrl, apiKey, reviewDeps, consumptionDeps, o
|
|
|
951
1002
|
function resetHeartbeatTimer() {
|
|
952
1003
|
clearHeartbeatTimer();
|
|
953
1004
|
heartbeatTimer = setTimeout(() => {
|
|
954
|
-
|
|
1005
|
+
log("No heartbeat received in 90s. Reconnecting...");
|
|
955
1006
|
ws.terminate();
|
|
956
1007
|
}, HEARTBEAT_TIMEOUT_MS);
|
|
957
1008
|
}
|
|
958
1009
|
ws.on("open", () => {
|
|
959
1010
|
connectionOpenedAt = Date.now();
|
|
960
|
-
|
|
1011
|
+
log("Connected to platform.");
|
|
961
1012
|
resetHeartbeatTimer();
|
|
962
1013
|
clearWsPingTimer();
|
|
963
1014
|
wsPingTimer = setInterval(() => {
|
|
@@ -969,12 +1020,12 @@ function startAgent(agentId, platformUrl, apiKey, reviewDeps, consumptionDeps, o
|
|
|
969
1020
|
}
|
|
970
1021
|
}, WS_PING_INTERVAL_MS);
|
|
971
1022
|
if (verbose) {
|
|
972
|
-
|
|
1023
|
+
log(`[verbose] Connection opened at ${new Date(connectionOpenedAt).toISOString()}`);
|
|
973
1024
|
}
|
|
974
1025
|
clearStabilityTimer();
|
|
975
1026
|
stabilityTimer = setTimeout(() => {
|
|
976
1027
|
if (verbose) {
|
|
977
|
-
|
|
1028
|
+
log(
|
|
978
1029
|
`[verbose] Connection stable for ${stabilityThreshold / 1e3}s \u2014 resetting reconnect counter`
|
|
979
1030
|
);
|
|
980
1031
|
}
|
|
@@ -988,7 +1039,17 @@ function startAgent(agentId, platformUrl, apiKey, reviewDeps, consumptionDeps, o
|
|
|
988
1039
|
} catch {
|
|
989
1040
|
return;
|
|
990
1041
|
}
|
|
991
|
-
handleMessage(
|
|
1042
|
+
handleMessage(
|
|
1043
|
+
ws,
|
|
1044
|
+
msg,
|
|
1045
|
+
resetHeartbeatTimer,
|
|
1046
|
+
reviewDeps,
|
|
1047
|
+
consumptionDeps,
|
|
1048
|
+
verbose,
|
|
1049
|
+
repoConfig,
|
|
1050
|
+
displayName,
|
|
1051
|
+
prefix
|
|
1052
|
+
);
|
|
992
1053
|
});
|
|
993
1054
|
ws.on("close", (code, reason) => {
|
|
994
1055
|
if (intentionalClose) return;
|
|
@@ -999,14 +1060,14 @@ function startAgent(agentId, platformUrl, apiKey, reviewDeps, consumptionDeps, o
|
|
|
999
1060
|
if (connectionOpenedAt) {
|
|
1000
1061
|
const lifetimeMs = Date.now() - connectionOpenedAt;
|
|
1001
1062
|
const lifetimeSec = (lifetimeMs / 1e3).toFixed(1);
|
|
1002
|
-
|
|
1063
|
+
log(
|
|
1003
1064
|
`Disconnected (code=${code}, reason=${reason.toString()}). Connection was alive for ${lifetimeSec}s.`
|
|
1004
1065
|
);
|
|
1005
1066
|
} else {
|
|
1006
|
-
|
|
1067
|
+
log(`Disconnected (code=${code}, reason=${reason.toString()}).`);
|
|
1007
1068
|
}
|
|
1008
1069
|
if (code === 4002) {
|
|
1009
|
-
|
|
1070
|
+
log("Connection replaced by server \u2014 not reconnecting.");
|
|
1010
1071
|
return;
|
|
1011
1072
|
}
|
|
1012
1073
|
connectionOpenedAt = null;
|
|
@@ -1014,18 +1075,18 @@ function startAgent(agentId, platformUrl, apiKey, reviewDeps, consumptionDeps, o
|
|
|
1014
1075
|
});
|
|
1015
1076
|
ws.on("pong", () => {
|
|
1016
1077
|
if (verbose) {
|
|
1017
|
-
|
|
1078
|
+
log(`[verbose] WS pong received at ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
1018
1079
|
}
|
|
1019
1080
|
});
|
|
1020
1081
|
ws.on("error", (err) => {
|
|
1021
|
-
|
|
1082
|
+
logError(`WebSocket error: ${err.message}`);
|
|
1022
1083
|
});
|
|
1023
1084
|
}
|
|
1024
1085
|
async function reconnect() {
|
|
1025
1086
|
const delay = calculateDelay(attempt, DEFAULT_RECONNECT_OPTIONS);
|
|
1026
1087
|
const delaySec = (delay / 1e3).toFixed(1);
|
|
1027
1088
|
attempt++;
|
|
1028
|
-
|
|
1089
|
+
log(`Reconnecting in ${delaySec}s... (attempt ${attempt})`);
|
|
1029
1090
|
await sleep(delay);
|
|
1030
1091
|
connect();
|
|
1031
1092
|
}
|
|
@@ -1038,16 +1099,17 @@ function trySend(ws, data) {
|
|
|
1038
1099
|
console.error("Failed to send message \u2014 WebSocket may be closed");
|
|
1039
1100
|
}
|
|
1040
1101
|
}
|
|
1041
|
-
async function logPostReviewStats(type, verdict, tokensUsed, tokensEstimated, consumptionDeps) {
|
|
1102
|
+
async function logPostReviewStats(type, verdict, tokensUsed, tokensEstimated, consumptionDeps, logPrefix) {
|
|
1103
|
+
const pfx = logPrefix ? `${logPrefix} ` : "";
|
|
1042
1104
|
const estimateTag = tokensEstimated ? " ~" : " ";
|
|
1043
1105
|
if (!consumptionDeps) {
|
|
1044
1106
|
if (verdict) {
|
|
1045
1107
|
console.log(
|
|
1046
|
-
`${type} complete: ${verdict} (${estimateTag}${tokensUsed} tokens${tokensEstimated ? ", estimated" : ""})`
|
|
1108
|
+
`${pfx}${type} complete: ${verdict} (${estimateTag}${tokensUsed} tokens${tokensEstimated ? ", estimated" : ""})`
|
|
1047
1109
|
);
|
|
1048
1110
|
} else {
|
|
1049
1111
|
console.log(
|
|
1050
|
-
`${type} complete (${estimateTag}${tokensUsed} tokens${tokensEstimated ? ", estimated" : ""})`
|
|
1112
|
+
`${pfx}${type} complete (${estimateTag}${tokensUsed} tokens${tokensEstimated ? ", estimated" : ""})`
|
|
1051
1113
|
);
|
|
1052
1114
|
}
|
|
1053
1115
|
return;
|
|
@@ -1055,37 +1117,43 @@ async function logPostReviewStats(type, verdict, tokensUsed, tokensEstimated, co
|
|
|
1055
1117
|
recordSessionUsage(consumptionDeps.session, tokensUsed);
|
|
1056
1118
|
if (verdict) {
|
|
1057
1119
|
console.log(
|
|
1058
|
-
`${type} complete: ${verdict} (${estimateTag}${tokensUsed.toLocaleString()} tokens${tokensEstimated ? ", estimated" : ""})`
|
|
1120
|
+
`${pfx}${type} complete: ${verdict} (${estimateTag}${tokensUsed.toLocaleString()} tokens${tokensEstimated ? ", estimated" : ""})`
|
|
1059
1121
|
);
|
|
1060
1122
|
} else {
|
|
1061
1123
|
console.log(
|
|
1062
|
-
`${type} complete (${estimateTag}${tokensUsed.toLocaleString()} tokens${tokensEstimated ? ", estimated" : ""})`
|
|
1124
|
+
`${pfx}${type} complete (${estimateTag}${tokensUsed.toLocaleString()} tokens${tokensEstimated ? ", estimated" : ""})`
|
|
1063
1125
|
);
|
|
1064
1126
|
}
|
|
1065
|
-
console.log(
|
|
1127
|
+
console.log(
|
|
1128
|
+
`${pfx}${formatPostReviewStats(tokensUsed, consumptionDeps.session, consumptionDeps.limits)}`
|
|
1129
|
+
);
|
|
1066
1130
|
}
|
|
1067
|
-
function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, verbose, repoConfig) {
|
|
1131
|
+
function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, verbose, repoConfig, displayName, logPrefix) {
|
|
1132
|
+
const pfx = logPrefix ? `${logPrefix} ` : "";
|
|
1068
1133
|
switch (msg.type) {
|
|
1069
1134
|
case "connected":
|
|
1070
|
-
console.log(
|
|
1135
|
+
console.log(`${pfx}Authenticated. Protocol v${msg.version ?? "unknown"}`);
|
|
1071
1136
|
trySend(ws, {
|
|
1072
1137
|
type: "agent_preferences",
|
|
1073
1138
|
id: crypto2.randomUUID(),
|
|
1074
1139
|
timestamp: Date.now(),
|
|
1140
|
+
...displayName ? { displayName } : {},
|
|
1075
1141
|
repoConfig: repoConfig ?? { mode: "all" }
|
|
1076
1142
|
});
|
|
1077
1143
|
break;
|
|
1078
1144
|
case "heartbeat_ping":
|
|
1079
1145
|
ws.send(JSON.stringify({ type: "heartbeat_pong", timestamp: Date.now() }));
|
|
1080
1146
|
if (verbose) {
|
|
1081
|
-
console.log(
|
|
1147
|
+
console.log(
|
|
1148
|
+
`${pfx}[verbose] Heartbeat ping received, pong sent at ${(/* @__PURE__ */ new Date()).toISOString()}`
|
|
1149
|
+
);
|
|
1082
1150
|
}
|
|
1083
1151
|
if (resetHeartbeat) resetHeartbeat();
|
|
1084
1152
|
break;
|
|
1085
1153
|
case "review_request": {
|
|
1086
1154
|
const request = msg;
|
|
1087
1155
|
console.log(
|
|
1088
|
-
|
|
1156
|
+
`${pfx}Review request: task ${request.taskId} for ${request.project.owner}/${request.project.repo}#${request.pr.number}`
|
|
1089
1157
|
);
|
|
1090
1158
|
if (!reviewDeps) {
|
|
1091
1159
|
ws.send(
|
|
@@ -1113,7 +1181,7 @@ function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, ver
|
|
|
1113
1181
|
taskId: request.taskId,
|
|
1114
1182
|
reason: limitResult.reason ?? "consumption_limit_exceeded"
|
|
1115
1183
|
});
|
|
1116
|
-
console.log(
|
|
1184
|
+
console.log(`${pfx}Review rejected: ${limitResult.reason}`);
|
|
1117
1185
|
return;
|
|
1118
1186
|
}
|
|
1119
1187
|
}
|
|
@@ -1145,7 +1213,8 @@ function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, ver
|
|
|
1145
1213
|
result.verdict,
|
|
1146
1214
|
result.tokensUsed,
|
|
1147
1215
|
result.tokensEstimated,
|
|
1148
|
-
consumptionDeps
|
|
1216
|
+
consumptionDeps,
|
|
1217
|
+
logPrefix
|
|
1149
1218
|
);
|
|
1150
1219
|
} catch (err) {
|
|
1151
1220
|
if (err instanceof DiffTooLargeError) {
|
|
@@ -1165,7 +1234,7 @@ function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, ver
|
|
|
1165
1234
|
error: err instanceof Error ? err.message : "Unknown error"
|
|
1166
1235
|
});
|
|
1167
1236
|
}
|
|
1168
|
-
console.error(
|
|
1237
|
+
console.error(`${pfx}Review failed:`, err);
|
|
1169
1238
|
}
|
|
1170
1239
|
})();
|
|
1171
1240
|
break;
|
|
@@ -1173,7 +1242,7 @@ function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, ver
|
|
|
1173
1242
|
case "summary_request": {
|
|
1174
1243
|
const summaryRequest = msg;
|
|
1175
1244
|
console.log(
|
|
1176
|
-
|
|
1245
|
+
`${pfx}Summary request: task ${summaryRequest.taskId} for ${summaryRequest.project.owner}/${summaryRequest.project.repo}#${summaryRequest.pr.number} (${summaryRequest.reviews.length} reviews)`
|
|
1177
1246
|
);
|
|
1178
1247
|
if (!reviewDeps) {
|
|
1179
1248
|
trySend(ws, {
|
|
@@ -1199,7 +1268,7 @@ function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, ver
|
|
|
1199
1268
|
taskId: summaryRequest.taskId,
|
|
1200
1269
|
reason: limitResult.reason ?? "consumption_limit_exceeded"
|
|
1201
1270
|
});
|
|
1202
|
-
console.log(
|
|
1271
|
+
console.log(`${pfx}Summary rejected: ${limitResult.reason}`);
|
|
1203
1272
|
return;
|
|
1204
1273
|
}
|
|
1205
1274
|
}
|
|
@@ -1230,7 +1299,8 @@ function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, ver
|
|
|
1230
1299
|
void 0,
|
|
1231
1300
|
result.tokensUsed,
|
|
1232
1301
|
result.tokensEstimated,
|
|
1233
|
-
consumptionDeps
|
|
1302
|
+
consumptionDeps,
|
|
1303
|
+
logPrefix
|
|
1234
1304
|
);
|
|
1235
1305
|
} catch (err) {
|
|
1236
1306
|
if (err instanceof InputTooLargeError) {
|
|
@@ -1250,13 +1320,13 @@ function handleMessage(ws, msg, resetHeartbeat, reviewDeps, consumptionDeps, ver
|
|
|
1250
1320
|
error: err instanceof Error ? err.message : "Summary failed"
|
|
1251
1321
|
});
|
|
1252
1322
|
}
|
|
1253
|
-
console.error(
|
|
1323
|
+
console.error(`${pfx}Summary failed:`, err);
|
|
1254
1324
|
}
|
|
1255
1325
|
})();
|
|
1256
1326
|
break;
|
|
1257
1327
|
}
|
|
1258
1328
|
case "error":
|
|
1259
|
-
console.error(
|
|
1329
|
+
console.error(`${pfx}Platform error: ${msg.code ?? "unknown"}`);
|
|
1260
1330
|
if (msg.code === "auth_revoked") process.exit(1);
|
|
1261
1331
|
break;
|
|
1262
1332
|
default:
|
|
@@ -1271,6 +1341,9 @@ async function syncAgentToServer(client, serverAgents, localAgent) {
|
|
|
1271
1341
|
return { agentId: existing.id, created: false };
|
|
1272
1342
|
}
|
|
1273
1343
|
const body = { model: localAgent.model, tool: localAgent.tool };
|
|
1344
|
+
if (localAgent.name) {
|
|
1345
|
+
body.displayName = localAgent.name;
|
|
1346
|
+
}
|
|
1274
1347
|
if (localAgent.repos) {
|
|
1275
1348
|
body.repoConfig = localAgent.repos;
|
|
1276
1349
|
}
|
|
@@ -1550,6 +1623,7 @@ agentCommand.command("start [agentIdOrModel]").description("Connect agent to pla
|
|
|
1550
1623
|
startAgent(entry.agentId, config.platformUrl, entry.apiKey, reviewDeps2, consumptionDeps2, {
|
|
1551
1624
|
verbose: opts.verbose,
|
|
1552
1625
|
stabilityThresholdMs,
|
|
1626
|
+
displayName: entry.name,
|
|
1553
1627
|
repoConfig: entry.repoConfig
|
|
1554
1628
|
});
|
|
1555
1629
|
return;
|
|
@@ -1659,11 +1733,13 @@ agentCommand.command("start [agentIdOrModel]").description("Connect agent to pla
|
|
|
1659
1733
|
limits: resolveAgentLimits(selected.local.limits, config.limits),
|
|
1660
1734
|
session: createSessionTracker()
|
|
1661
1735
|
};
|
|
1662
|
-
|
|
1736
|
+
const label = selected.local.name || selected.local.model || "unnamed";
|
|
1737
|
+
console.log(`Starting agent ${label} (${agentId2})...`);
|
|
1663
1738
|
startAgent(agentId2, config.platformUrl, apiKey2, reviewDeps2, consumptionDeps2, {
|
|
1664
1739
|
verbose: opts.verbose,
|
|
1665
1740
|
stabilityThresholdMs,
|
|
1666
|
-
repoConfig: selected.local.repos
|
|
1741
|
+
repoConfig: selected.local.repos,
|
|
1742
|
+
label
|
|
1667
1743
|
});
|
|
1668
1744
|
startedCount++;
|
|
1669
1745
|
}
|
|
@@ -1692,11 +1768,14 @@ agentCommand.command("start [agentIdOrModel]").description("Connect agent to pla
|
|
|
1692
1768
|
limits: config.limits,
|
|
1693
1769
|
session: createSessionTracker()
|
|
1694
1770
|
};
|
|
1695
|
-
|
|
1771
|
+
const anonLabel = anon.name || anon.model || "anonymous";
|
|
1772
|
+
console.log(`Starting anonymous agent ${anonLabel} (${anon.agentId})...`);
|
|
1696
1773
|
startAgent(anon.agentId, config.platformUrl, anon.apiKey, reviewDeps2, consumptionDeps2, {
|
|
1697
1774
|
verbose: opts.verbose,
|
|
1698
1775
|
stabilityThresholdMs,
|
|
1699
|
-
|
|
1776
|
+
displayName: anon.name,
|
|
1777
|
+
repoConfig: anon.repoConfig,
|
|
1778
|
+
label: anonLabel
|
|
1700
1779
|
});
|
|
1701
1780
|
startedCount++;
|
|
1702
1781
|
}
|
|
@@ -1755,7 +1834,8 @@ agentCommand.command("start [agentIdOrModel]").description("Connect agent to pla
|
|
|
1755
1834
|
console.log(`Starting agent ${agentId}...`);
|
|
1756
1835
|
startAgent(agentId, config.platformUrl, apiKey, reviewDeps, consumptionDeps, {
|
|
1757
1836
|
verbose: opts.verbose,
|
|
1758
|
-
stabilityThresholdMs
|
|
1837
|
+
stabilityThresholdMs,
|
|
1838
|
+
label: agentId
|
|
1759
1839
|
});
|
|
1760
1840
|
}
|
|
1761
1841
|
);
|
|
@@ -1936,7 +2016,7 @@ var statsCommand = new Command3("stats").description("Display agent dashboard: t
|
|
|
1936
2016
|
});
|
|
1937
2017
|
|
|
1938
2018
|
// src/index.ts
|
|
1939
|
-
var program = new Command4().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version("0.
|
|
2019
|
+
var program = new Command4().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version("0.8.0");
|
|
1940
2020
|
program.addCommand(loginCommand);
|
|
1941
2021
|
program.addCommand(agentCommand);
|
|
1942
2022
|
program.addCommand(statsCommand);
|