baro-ai 0.34.0 → 0.36.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/cli.mjs +104 -29
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -7672,17 +7672,6 @@ var AgenticEnvironment = class {
|
|
|
7672
7672
|
this.isActive = false;
|
|
7673
7673
|
}
|
|
7674
7674
|
};
|
|
7675
|
-
var OpenAIInferenceRunner = class {
|
|
7676
|
-
constructor() {
|
|
7677
|
-
this.runtime = new OpenAIResponses();
|
|
7678
|
-
}
|
|
7679
|
-
async *run(context, model, signal) {
|
|
7680
|
-
const response = await this.runtime.infer(new InferenceRequest(model, context));
|
|
7681
|
-
for (const item of response.contextItems) {
|
|
7682
|
-
yield item;
|
|
7683
|
-
}
|
|
7684
|
-
}
|
|
7685
|
-
};
|
|
7686
7675
|
var Gpt55 = class {
|
|
7687
7676
|
constructor() {
|
|
7688
7677
|
this.specification = {
|
|
@@ -8560,6 +8549,7 @@ function markStoryPassed(prd, storyId, durationSecs) {
|
|
|
8560
8549
|
)
|
|
8561
8550
|
};
|
|
8562
8551
|
}
|
|
8552
|
+
var BARO_COAUTHOR_TRAILER = "Co-Authored-By: baro <285254893+baro-rs@users.noreply.github.com>";
|
|
8563
8553
|
function buildDefaultStoryPrompt(story) {
|
|
8564
8554
|
const acceptance = story.acceptance.length ? story.acceptance.map((a, i) => `${i + 1}. ${a}`).join("\n") : "(none specified)";
|
|
8565
8555
|
const tests = story.tests.length ? story.tests.map((t) => `- ${t}`).join("\n") : "(no test commands specified)";
|
|
@@ -8593,7 +8583,18 @@ function buildDefaultStoryPrompt(story) {
|
|
|
8593
8583
|
" - If pyproject.toml or requirements.txt: ensure code is import-clean",
|
|
8594
8584
|
" - Otherwise: ensure linting/typecheck passes",
|
|
8595
8585
|
"",
|
|
8596
|
-
"When done with the story, commit your changes with a clear message."
|
|
8586
|
+
"When done with the story, commit your changes with a clear message.",
|
|
8587
|
+
"",
|
|
8588
|
+
"COMMIT MESSAGE TRAILER (mandatory):",
|
|
8589
|
+
"Every commit you create as part of this story MUST end with a blank line",
|
|
8590
|
+
"followed by this exact trailer line \u2014 no edits, no surrounding text:",
|
|
8591
|
+
"",
|
|
8592
|
+
` ${BARO_COAUTHOR_TRAILER}`,
|
|
8593
|
+
"",
|
|
8594
|
+
'Use `git commit -m "\u2026" -m "" -m "' + BARO_COAUTHOR_TRAILER + '"` so the',
|
|
8595
|
+
"trailer lands on its own paragraph at the bottom (git collapses the empty",
|
|
8596
|
+
"middle `-m` to a blank line between the subject and the trailer). This",
|
|
8597
|
+
"attributes the commit to the baro account in the contributors view."
|
|
8597
8598
|
].join("\n");
|
|
8598
8599
|
}
|
|
8599
8600
|
|
|
@@ -9876,6 +9877,58 @@ function extractVerdictJson(text) {
|
|
|
9876
9877
|
throw new Error(`unbalanced JSON object in critic response: ${trimmed.slice(0, 200)}`);
|
|
9877
9878
|
}
|
|
9878
9879
|
|
|
9880
|
+
// ../baro-orchestrator/src/planning/openai-runtime.ts
|
|
9881
|
+
var runtime = new OpenAIResponses();
|
|
9882
|
+
async function runInferenceRound(context, model) {
|
|
9883
|
+
const response = await runtime.infer(new InferenceRequest(model, context));
|
|
9884
|
+
return {
|
|
9885
|
+
items: response.contextItems,
|
|
9886
|
+
usage: response.tokenUsage
|
|
9887
|
+
};
|
|
9888
|
+
}
|
|
9889
|
+
var UsageAccumulator = class {
|
|
9890
|
+
input = 0;
|
|
9891
|
+
output = 0;
|
|
9892
|
+
total = 0;
|
|
9893
|
+
cached = 0;
|
|
9894
|
+
reasoning = 0;
|
|
9895
|
+
rounds = 0;
|
|
9896
|
+
add(usage) {
|
|
9897
|
+
if (!usage) return;
|
|
9898
|
+
this.rounds += 1;
|
|
9899
|
+
this.input += usage.inputTokens ?? 0;
|
|
9900
|
+
this.output += usage.outputTokens ?? 0;
|
|
9901
|
+
this.total += usage.totalTokens ?? 0;
|
|
9902
|
+
this.cached += usage.inputTokenDetails?.cached_tokens ?? 0;
|
|
9903
|
+
this.reasoning += usage.outputTokenDetails?.reasoning_tokens ?? 0;
|
|
9904
|
+
}
|
|
9905
|
+
get isEmpty() {
|
|
9906
|
+
return this.rounds === 0;
|
|
9907
|
+
}
|
|
9908
|
+
/**
|
|
9909
|
+
* Plain-object snapshot suitable for embedding in
|
|
9910
|
+
* `AgentResultItem.usage` (which is typed `any` to allow per-
|
|
9911
|
+
* provider shapes). Keys are snake_case to line up with what the
|
|
9912
|
+
* Claude side's stream-json mapper produces from Anthropic
|
|
9913
|
+
* usage frames.
|
|
9914
|
+
*/
|
|
9915
|
+
toJSON() {
|
|
9916
|
+
return {
|
|
9917
|
+
input_tokens: this.input,
|
|
9918
|
+
output_tokens: this.output,
|
|
9919
|
+
total_tokens: this.total,
|
|
9920
|
+
cached_input_tokens: this.cached,
|
|
9921
|
+
reasoning_tokens: this.reasoning,
|
|
9922
|
+
rounds: this.rounds
|
|
9923
|
+
};
|
|
9924
|
+
}
|
|
9925
|
+
/** One-line summary for the stderr / log path. */
|
|
9926
|
+
summary() {
|
|
9927
|
+
if (this.isEmpty) return "(no token usage reported)";
|
|
9928
|
+
return `${this.total} total tokens (${this.input} in, ${this.output} out${this.cached ? `, ${this.cached} cached` : ""}${this.reasoning ? `, ${this.reasoning} reasoning` : ""}) across ${this.rounds} round(s)`;
|
|
9929
|
+
}
|
|
9930
|
+
};
|
|
9931
|
+
|
|
9879
9932
|
// ../baro-orchestrator/src/participants/critic-openai.ts
|
|
9880
9933
|
function pickModel(name) {
|
|
9881
9934
|
switch (name) {
|
|
@@ -9896,7 +9949,6 @@ function pickModel(name) {
|
|
|
9896
9949
|
var CriticOpenAI = class extends BaroParticipant {
|
|
9897
9950
|
opts;
|
|
9898
9951
|
model;
|
|
9899
|
-
runner = new OpenAIInferenceRunner();
|
|
9900
9952
|
emissions = /* @__PURE__ */ new Map();
|
|
9901
9953
|
turnCount = /* @__PURE__ */ new Map();
|
|
9902
9954
|
pending = /* @__PURE__ */ new Set();
|
|
@@ -9967,9 +10019,12 @@ var CriticOpenAI = class extends BaroParticipant {
|
|
|
9967
10019
|
const userPrompt = buildEvalPrompt(criteria, resultText);
|
|
9968
10020
|
const context = ModelContext.create("critic").addContextItem(SystemMessageItem.create(VERDICT_SYSTEM_PROMPT)).addContextItem(UserMessageItem.create(userPrompt));
|
|
9969
10021
|
try {
|
|
10022
|
+
const round = await runInferenceRound(context, this.model);
|
|
10023
|
+
const usage = new UsageAccumulator();
|
|
10024
|
+
usage.add(round.usage);
|
|
9970
10025
|
let assistantText = "";
|
|
9971
|
-
for
|
|
9972
|
-
if (item.type === "message"
|
|
10026
|
+
for (const item of round.items) {
|
|
10027
|
+
if (item.type === "message") {
|
|
9973
10028
|
const json = item.toJSON();
|
|
9974
10029
|
assistantText += json.content?.[0]?.text ?? "";
|
|
9975
10030
|
}
|
|
@@ -9977,6 +10032,8 @@ var CriticOpenAI = class extends BaroParticipant {
|
|
|
9977
10032
|
if (!assistantText.trim()) {
|
|
9978
10033
|
throw new Error("OpenAI returned empty assistant text");
|
|
9979
10034
|
}
|
|
10035
|
+
process.stderr.write(`[critic-openai] ${usage.summary()}
|
|
10036
|
+
`);
|
|
9980
10037
|
const verdictJson = extractVerdictJson(assistantText);
|
|
9981
10038
|
const parsed = JSON.parse(verdictJson);
|
|
9982
10039
|
return {
|
|
@@ -10365,6 +10422,8 @@ var Finalizer = class extends BaroParticipant {
|
|
|
10365
10422
|
lines.push("---");
|
|
10366
10423
|
lines.push("");
|
|
10367
10424
|
lines.push("\u{1F916} Plan. Parallelize. Review. Ship. \u2014 opened by baro");
|
|
10425
|
+
lines.push("");
|
|
10426
|
+
lines.push(BARO_COAUTHOR_TRAILER);
|
|
10368
10427
|
return lines.join("\n");
|
|
10369
10428
|
}
|
|
10370
10429
|
async hasGhBinary() {
|
|
@@ -11266,7 +11325,6 @@ var OpenAIStoryAgent = class extends BaroParticipant {
|
|
|
11266
11325
|
spec;
|
|
11267
11326
|
opts;
|
|
11268
11327
|
model;
|
|
11269
|
-
runner = new OpenAIInferenceRunner();
|
|
11270
11328
|
tools;
|
|
11271
11329
|
envRef = null;
|
|
11272
11330
|
currentPhase = "idle";
|
|
@@ -11381,6 +11439,7 @@ var OpenAIStoryAgent = class extends BaroParticipant {
|
|
|
11381
11439
|
for (let turn = 1; turn <= this.spec.maxTurns; turn++) {
|
|
11382
11440
|
const turnResult = await this.runOneTurn(context);
|
|
11383
11441
|
context = turnResult.context;
|
|
11442
|
+
const usageJson = turnResult.usage.isEmpty ? null : turnResult.usage.toJSON();
|
|
11384
11443
|
this.envRef?.deliverBusEvent(
|
|
11385
11444
|
this,
|
|
11386
11445
|
new AgentResultItem(
|
|
@@ -11390,14 +11449,17 @@ var OpenAIStoryAgent = class extends BaroParticipant {
|
|
|
11390
11449
|
// session id — not applicable for OpenAI
|
|
11391
11450
|
!turnResult.success,
|
|
11392
11451
|
turnResult.assistantText,
|
|
11393
|
-
|
|
11394
|
-
// usage info — not surfaced this phase
|
|
11452
|
+
usageJson,
|
|
11395
11453
|
null,
|
|
11396
11454
|
null,
|
|
11397
11455
|
null,
|
|
11398
11456
|
{}
|
|
11399
11457
|
)
|
|
11400
11458
|
);
|
|
11459
|
+
process.stderr.write(
|
|
11460
|
+
`[story-openai/${this.spec.id}] turn ${turn}: ${turnResult.usage.summary()}
|
|
11461
|
+
`
|
|
11462
|
+
);
|
|
11401
11463
|
if (!turnResult.success) {
|
|
11402
11464
|
this.transition("failed", turnResult.error ?? "turn failed");
|
|
11403
11465
|
return;
|
|
@@ -11428,19 +11490,27 @@ var OpenAIStoryAgent = class extends BaroParticipant {
|
|
|
11428
11490
|
let context = initialContext;
|
|
11429
11491
|
let assistantText = null;
|
|
11430
11492
|
const perRoundMs = this.opts.perRoundTimeoutSecs * 1e3;
|
|
11493
|
+
const usage = new UsageAccumulator();
|
|
11431
11494
|
for (let round = 1; round <= this.opts.maxRoundsPerTurn; round++) {
|
|
11432
|
-
const ac = new AbortController();
|
|
11433
|
-
const timer = setTimeout(() => ac.abort(), perRoundMs);
|
|
11434
11495
|
const calls = [];
|
|
11435
11496
|
let sawMessage = false;
|
|
11436
11497
|
let lastMessageText = null;
|
|
11437
11498
|
try {
|
|
11438
|
-
|
|
11499
|
+
const roundPromise = runInferenceRound(context, this.model);
|
|
11500
|
+
const timeoutPromise = new Promise(
|
|
11501
|
+
(_, rej) => setTimeout(
|
|
11502
|
+
() => rej(new Error(`round ${round} timed out after ${perRoundMs}ms`)),
|
|
11503
|
+
perRoundMs
|
|
11504
|
+
)
|
|
11505
|
+
);
|
|
11506
|
+
const result = await Promise.race([roundPromise, timeoutPromise]);
|
|
11507
|
+
usage.add(result.usage);
|
|
11508
|
+
for (const item of result.items) {
|
|
11439
11509
|
if (item.type === "function_call") {
|
|
11440
11510
|
await this.envRef?.deliverFunctionCall(this, item);
|
|
11441
11511
|
context = context.addContextItem(item);
|
|
11442
11512
|
calls.push(item);
|
|
11443
|
-
} else if (item.type === "message"
|
|
11513
|
+
} else if (item.type === "message") {
|
|
11444
11514
|
await this.envRef?.deliverModelMessage(this, item);
|
|
11445
11515
|
context = context.addContextItem(item);
|
|
11446
11516
|
const json = item.toJSON();
|
|
@@ -11452,15 +11522,13 @@ var OpenAIStoryAgent = class extends BaroParticipant {
|
|
|
11452
11522
|
}
|
|
11453
11523
|
}
|
|
11454
11524
|
} catch (e) {
|
|
11455
|
-
clearTimeout(timer);
|
|
11456
11525
|
return {
|
|
11457
11526
|
context,
|
|
11458
11527
|
success: false,
|
|
11459
11528
|
assistantText,
|
|
11529
|
+
usage,
|
|
11460
11530
|
error: `inference round ${round} failed: ${e?.message ?? String(e)}`
|
|
11461
11531
|
};
|
|
11462
|
-
} finally {
|
|
11463
|
-
clearTimeout(timer);
|
|
11464
11532
|
}
|
|
11465
11533
|
for (const call of calls) {
|
|
11466
11534
|
const tool = this.tools.find((t) => t.name === call.name);
|
|
@@ -11473,7 +11541,8 @@ var OpenAIStoryAgent = class extends BaroParticipant {
|
|
|
11473
11541
|
return {
|
|
11474
11542
|
context,
|
|
11475
11543
|
success: true,
|
|
11476
|
-
assistantText: lastMessageText
|
|
11544
|
+
assistantText: lastMessageText,
|
|
11545
|
+
usage
|
|
11477
11546
|
};
|
|
11478
11547
|
}
|
|
11479
11548
|
if (!sawMessage && calls.length === 0) {
|
|
@@ -11481,6 +11550,7 @@ var OpenAIStoryAgent = class extends BaroParticipant {
|
|
|
11481
11550
|
context,
|
|
11482
11551
|
success: false,
|
|
11483
11552
|
assistantText,
|
|
11553
|
+
usage,
|
|
11484
11554
|
error: `round ${round} returned no items`
|
|
11485
11555
|
};
|
|
11486
11556
|
}
|
|
@@ -11490,6 +11560,7 @@ var OpenAIStoryAgent = class extends BaroParticipant {
|
|
|
11490
11560
|
context,
|
|
11491
11561
|
success: false,
|
|
11492
11562
|
assistantText,
|
|
11563
|
+
usage,
|
|
11493
11564
|
error: `exceeded maxRoundsPerTurn=${this.opts.maxRoundsPerTurn}`
|
|
11494
11565
|
};
|
|
11495
11566
|
}
|
|
@@ -11852,7 +11923,6 @@ function pickModel3(name) {
|
|
|
11852
11923
|
var SurgeonOpenAI = class extends BaroParticipant {
|
|
11853
11924
|
opts;
|
|
11854
11925
|
model;
|
|
11855
|
-
runner = new OpenAIInferenceRunner();
|
|
11856
11926
|
replansEmitted = 0;
|
|
11857
11927
|
pending = /* @__PURE__ */ new Set();
|
|
11858
11928
|
constructor(opts) {
|
|
@@ -11896,9 +11966,12 @@ var SurgeonOpenAI = class extends BaroParticipant {
|
|
|
11896
11966
|
const userPrompt = buildSurgeonPrompt(snap, failure);
|
|
11897
11967
|
const context = ModelContext.create("surgeon").addContextItem(SystemMessageItem.create(SURGEON_SYSTEM_PROMPT)).addContextItem(UserMessageItem.create(userPrompt));
|
|
11898
11968
|
try {
|
|
11969
|
+
const round = await runInferenceRound(context, this.model);
|
|
11970
|
+
const usage = new UsageAccumulator();
|
|
11971
|
+
usage.add(round.usage);
|
|
11899
11972
|
let assistantText = "";
|
|
11900
|
-
for
|
|
11901
|
-
if (item.type === "message"
|
|
11973
|
+
for (const item of round.items) {
|
|
11974
|
+
if (item.type === "message") {
|
|
11902
11975
|
const json = item.toJSON();
|
|
11903
11976
|
assistantText += json.content?.[0]?.text ?? "";
|
|
11904
11977
|
}
|
|
@@ -11906,6 +11979,8 @@ var SurgeonOpenAI = class extends BaroParticipant {
|
|
|
11906
11979
|
if (!assistantText.trim()) {
|
|
11907
11980
|
throw new Error("OpenAI returned empty assistant text");
|
|
11908
11981
|
}
|
|
11982
|
+
process.stderr.write(`[surgeon-openai] ${usage.summary()}
|
|
11983
|
+
`);
|
|
11909
11984
|
const verdictJson = extractJsonObject(assistantText);
|
|
11910
11985
|
const parsed = JSON.parse(verdictJson);
|
|
11911
11986
|
if (parsed.action === "abort") return null;
|