@wrongstack/core 0.299.0 → 0.300.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/coordination/director.d.ts +8 -0
- package/dist/coordination/fleet-manager.d.ts +48 -3
- package/dist/coordination/ifleet-manager.d.ts +2 -0
- package/dist/coordination/index.js +120 -20
- package/dist/coordination/multi-agent-coordinator.d.ts +1 -0
- package/dist/core/fallback-model.d.ts +48 -0
- package/dist/core/index.d.ts +3 -2
- package/dist/core/index.js +226 -26
- package/dist/core/instruction-template.d.ts +80 -0
- package/dist/core/system-prompt-blocks.d.ts +10 -1
- package/dist/core/system-prompt-builder.d.ts +35 -1
- package/dist/defaults/index.js +238 -99
- package/dist/execution/autonomy-brain.d.ts +7 -0
- package/dist/execution/council-brain.d.ts +11 -0
- package/dist/execution/council-orchestrator.d.ts +23 -4
- package/dist/execution/council-prompts.d.ts +12 -1
- package/dist/execution/index.js +355 -138
- package/dist/fleet-notifier.d.ts +9 -2
- package/dist/hooks/index.js +8 -4
- package/dist/hq/index.js +18 -4
- package/dist/hq/protocol/fleet.d.ts +20 -0
- package/dist/hq/protocol.js +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1512 -707
- package/dist/kernel/events/brain-events.d.ts +9 -0
- package/dist/kernel/events/provider-events.d.ts +42 -1
- package/dist/models/index.js +1 -1
- package/dist/plugin/api.d.ts +6 -0
- package/dist/plugin/config.d.ts +55 -0
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/index.js +134 -21
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +157 -42
- package/dist/security/permission-helpers.d.ts +23 -6
- package/dist/security/permission-policy.d.ts +16 -0
- package/dist/security/totp.d.ts +14 -0
- package/dist/storage/director-state.d.ts +7 -0
- package/dist/storage/index.js +33 -8
- package/dist/tools/fallback-system-config-view-tool.d.ts +1 -1
- package/dist/tools/index.js +388 -102
- package/dist/types/council.d.ts +11 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/multi-agent.d.ts +10 -0
- package/dist/types/one-shot-llm.d.ts +9 -0
- package/dist/types/plugin.d.ts +28 -0
- package/dist/worktree/index.js +4 -4
- package/instructions/system-lite.md +81 -3
- package/instructions/system-pro.md +275 -90
- package/instructions/system.md +228 -81
- package/package.json +3 -3
package/dist/execution/index.js
CHANGED
|
@@ -3979,7 +3979,11 @@ async function completeBrainLlm(target, input) {
|
|
|
3979
3979
|
return (await completeBrainLlmDetailed(target, input)).text;
|
|
3980
3980
|
}
|
|
3981
3981
|
async function completeBrainLlmDetailed(target, input) {
|
|
3982
|
-
|
|
3982
|
+
if (input.signal?.aborted) {
|
|
3983
|
+
throw new DOMException("Brain call aborted before it started.", "AbortError");
|
|
3984
|
+
}
|
|
3985
|
+
const timeoutSignal = AbortSignal.timeout(input.timeoutMs);
|
|
3986
|
+
const signal = input.signal ? AbortSignal.any([input.signal, timeoutSignal]) : timeoutSignal;
|
|
3983
3987
|
const response = await target.provider.complete(
|
|
3984
3988
|
{
|
|
3985
3989
|
model: target.model,
|
|
@@ -5174,22 +5178,29 @@ function buildCouncilJudgeUserPrompt(question, votes, opts = {}) {
|
|
|
5174
5178
|
"</council-ballots>"
|
|
5175
5179
|
].filter(Boolean).join("\n\n");
|
|
5176
5180
|
}
|
|
5177
|
-
function
|
|
5178
|
-
|
|
5181
|
+
function validateCouncilOptions(options) {
|
|
5182
|
+
const errors = [];
|
|
5179
5183
|
const seen = /* @__PURE__ */ new Set();
|
|
5180
|
-
|
|
5184
|
+
for (const option of options ?? []) {
|
|
5181
5185
|
const id = option.id.trim();
|
|
5182
|
-
|
|
5183
|
-
if (!
|
|
5184
|
-
if (
|
|
5185
|
-
if (seen.has(id)) throw new Error(`buildCouncilQuestionPrompt: duplicate option id "${id}".`);
|
|
5186
|
+
if (!id) errors.push("Every option must have a non-empty `id`.");
|
|
5187
|
+
if (!option.label.trim()) errors.push(`Option "${id || "<empty>"}" must have a label.`);
|
|
5188
|
+
if (seen.has(id)) errors.push(`Duplicate option id "${id}".`);
|
|
5186
5189
|
seen.add(id);
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5190
|
+
}
|
|
5191
|
+
return errors;
|
|
5192
|
+
}
|
|
5193
|
+
function normalizeOptions(options) {
|
|
5194
|
+
if (!options) return [];
|
|
5195
|
+
const errors = validateCouncilOptions(options);
|
|
5196
|
+
if (errors.length > 0) {
|
|
5197
|
+
throw new Error(`buildCouncilQuestionPrompt: ${errors.join("; ")}`);
|
|
5198
|
+
}
|
|
5199
|
+
return options.map((option) => ({
|
|
5200
|
+
id: option.id.trim(),
|
|
5201
|
+
label: option.label.trim(),
|
|
5202
|
+
...option.consequence?.trim() ? { consequence: option.consequence.trim() } : {}
|
|
5203
|
+
}));
|
|
5193
5204
|
}
|
|
5194
5205
|
function requiredInstruction(path17) {
|
|
5195
5206
|
const text = readBundledInstructionText(path17);
|
|
@@ -5297,6 +5308,8 @@ function requireFraction(value, label) {
|
|
|
5297
5308
|
var COUNCIL_REFUSAL_OPTION_ID = "council_refuse";
|
|
5298
5309
|
var DEFAULT_COUNCIL_MAX_CONCURRENCY = 3;
|
|
5299
5310
|
var MAX_COUNCIL_CONCURRENCY = 8;
|
|
5311
|
+
var OVERALL_TIMEOUT_REASON = "Council overall timeout exceeded.";
|
|
5312
|
+
var CALL_CANCELLED_REASON = "Cancelled.";
|
|
5300
5313
|
var CouncilOrchestrator = class {
|
|
5301
5314
|
caller;
|
|
5302
5315
|
personas;
|
|
@@ -5307,6 +5320,17 @@ var CouncilOrchestrator = class {
|
|
|
5307
5320
|
fallbackProfileManager;
|
|
5308
5321
|
seatCaller;
|
|
5309
5322
|
judgeCaller;
|
|
5323
|
+
/**
|
|
5324
|
+
* Normalized ad-hoc profiles keyed by the caller's config object identity.
|
|
5325
|
+
* The Brain adapter reuses ONE profile object for every decision, so this
|
|
5326
|
+
* avoids re-validating + re-freezing it on every ask() without caching
|
|
5327
|
+
* string-keyed registry lookups (those are already O(1)).
|
|
5328
|
+
*
|
|
5329
|
+
* Hosts must treat ad-hoc profile configs as IMMUTABLE once passed to
|
|
5330
|
+
* ask(): the cache is keyed by object identity and never invalidated, so
|
|
5331
|
+
* mutating a cached profile would silently serve the first snapshot.
|
|
5332
|
+
*/
|
|
5333
|
+
profileCache = /* @__PURE__ */ new WeakMap();
|
|
5310
5334
|
constructor(opts) {
|
|
5311
5335
|
if (!opts.caller && !opts.seatCaller && !opts.judgeCaller) {
|
|
5312
5336
|
throw new Error(
|
|
@@ -5325,13 +5349,33 @@ var CouncilOrchestrator = class {
|
|
|
5325
5349
|
this.seatCaller = opts.seatCaller;
|
|
5326
5350
|
this.judgeCaller = opts.judgeCaller;
|
|
5327
5351
|
}
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5352
|
+
/**
|
|
5353
|
+
* Resolve the effective profile for a question. String ids and the default
|
|
5354
|
+
* go through the registry (already O(1)); ad-hoc config objects are
|
|
5355
|
+
* normalized once per stable object identity and cached, because hosts such
|
|
5356
|
+
* as the Brain adapter pass the same profile object on every ask().
|
|
5357
|
+
*/
|
|
5358
|
+
resolveProfile(profile) {
|
|
5359
|
+
if (typeof profile === "string" || profile === void 0) {
|
|
5360
|
+
return resolveCouncilProfile(profile, {
|
|
5361
|
+
registry: this.profiles,
|
|
5362
|
+
personas: this.personas,
|
|
5363
|
+
defaultProfile: this.defaultProfile
|
|
5364
|
+
});
|
|
5365
|
+
}
|
|
5366
|
+
const cached = this.profileCache.get(profile);
|
|
5367
|
+
if (cached) return cached;
|
|
5368
|
+
const resolved = resolveCouncilProfile(profile, {
|
|
5331
5369
|
registry: this.profiles,
|
|
5332
5370
|
personas: this.personas,
|
|
5333
5371
|
defaultProfile: this.defaultProfile
|
|
5334
5372
|
});
|
|
5373
|
+
this.profileCache.set(profile, resolved);
|
|
5374
|
+
return resolved;
|
|
5375
|
+
}
|
|
5376
|
+
async ask(question) {
|
|
5377
|
+
const startedAt = Date.now();
|
|
5378
|
+
const profile = this.resolveProfile(question.profile);
|
|
5335
5379
|
validateRefusalCollision(question, this.refusalOptionId);
|
|
5336
5380
|
const timeoutSignal = AbortSignal.timeout(profile.overallTimeoutMs);
|
|
5337
5381
|
const signal = question.signal ? AbortSignal.any([question.signal, timeoutSignal]) : timeoutSignal;
|
|
@@ -5348,11 +5392,16 @@ var CouncilOrchestrator = class {
|
|
|
5348
5392
|
try {
|
|
5349
5393
|
return await this.callSeat(question, profile, seat, i, signal, usage);
|
|
5350
5394
|
} catch (error) {
|
|
5395
|
+
const timedOut = signal.aborted && !question.signal?.aborted;
|
|
5351
5396
|
return {
|
|
5352
5397
|
seatId: seat.id,
|
|
5353
5398
|
persona: seat.persona,
|
|
5354
|
-
|
|
5355
|
-
|
|
5399
|
+
// Only the caller's own cancel is a "cancelled" vote; the overall
|
|
5400
|
+
// budget expiring is a failure (timeout), matching the envelope.
|
|
5401
|
+
status: question.signal?.aborted ? "cancelled" : "failed",
|
|
5402
|
+
// Canonical text for aborted-by-budget or cancelled seats, so one
|
|
5403
|
+
// event does not surface a different string per code path.
|
|
5404
|
+
error: question.signal?.aborted ? CALL_CANCELLED_REASON : timedOut ? OVERALL_TIMEOUT_REASON : errorMessage(error)
|
|
5356
5405
|
};
|
|
5357
5406
|
}
|
|
5358
5407
|
}
|
|
@@ -5362,7 +5411,7 @@ var CouncilOrchestrator = class {
|
|
|
5362
5411
|
if (question.signal?.aborted) {
|
|
5363
5412
|
return resultEnvelope({
|
|
5364
5413
|
status: "cancelled",
|
|
5365
|
-
reason:
|
|
5414
|
+
reason: CALL_CANCELLED_REASON,
|
|
5366
5415
|
resolution: "none",
|
|
5367
5416
|
votes,
|
|
5368
5417
|
profile,
|
|
@@ -5375,14 +5424,17 @@ var CouncilOrchestrator = class {
|
|
|
5375
5424
|
if (timeoutSignal.aborted) {
|
|
5376
5425
|
return resultEnvelope({
|
|
5377
5426
|
status: "failed",
|
|
5378
|
-
reason:
|
|
5427
|
+
reason: OVERALL_TIMEOUT_REASON,
|
|
5379
5428
|
resolution: "none",
|
|
5380
5429
|
votes,
|
|
5381
5430
|
profile,
|
|
5382
5431
|
usage,
|
|
5383
5432
|
startedAt,
|
|
5384
5433
|
warnings,
|
|
5385
|
-
|
|
5434
|
+
// Seat-prefixed errors normally carry the canonical timeout text, but
|
|
5435
|
+
// a signal-blind caller can resolve valid votes even after the budget
|
|
5436
|
+
// expired — append the standalone entry only when nothing carries it.
|
|
5437
|
+
errors: errors.some((entry) => entry.includes(OVERALL_TIMEOUT_REASON)) ? errors : [...errors, OVERALL_TIMEOUT_REASON]
|
|
5386
5438
|
});
|
|
5387
5439
|
}
|
|
5388
5440
|
if (!question.options || question.options.length === 0) {
|
|
@@ -5409,7 +5461,17 @@ var CouncilOrchestrator = class {
|
|
|
5409
5461
|
);
|
|
5410
5462
|
}
|
|
5411
5463
|
async callSeat(question, profile, seat, seatIndex, signal, usage) {
|
|
5412
|
-
if (signal.aborted)
|
|
5464
|
+
if (signal.aborted) {
|
|
5465
|
+
return question.signal?.aborted ? cancelledVote(seat) : {
|
|
5466
|
+
seatId: seat.id,
|
|
5467
|
+
persona: seat.persona,
|
|
5468
|
+
status: "failed",
|
|
5469
|
+
...seat.target?.providerId ? { provider: seat.target.providerId } : {},
|
|
5470
|
+
...seat.target?.model ? { model: seat.target.model } : {},
|
|
5471
|
+
durationMs: 0,
|
|
5472
|
+
error: OVERALL_TIMEOUT_REASON
|
|
5473
|
+
};
|
|
5474
|
+
}
|
|
5413
5475
|
let persona;
|
|
5414
5476
|
try {
|
|
5415
5477
|
persona = this.personas.require(seat.persona);
|
|
@@ -5435,12 +5497,15 @@ var CouncilOrchestrator = class {
|
|
|
5435
5497
|
});
|
|
5436
5498
|
const metadata = callMetadata(result);
|
|
5437
5499
|
if (result.error) {
|
|
5500
|
+
const timedOut = signal.aborted && !question.signal?.aborted;
|
|
5438
5501
|
return {
|
|
5439
5502
|
seatId: seat.id,
|
|
5440
5503
|
persona: seat.persona,
|
|
5441
|
-
status: signal
|
|
5504
|
+
status: question.signal?.aborted ? "cancelled" : "failed",
|
|
5442
5505
|
...metadata,
|
|
5443
|
-
|
|
5506
|
+
// Canonical text for cancelled or aborted-by-budget seats, so one
|
|
5507
|
+
// cancel/timeout event does not surface a raw provider string.
|
|
5508
|
+
error: question.signal?.aborted ? CALL_CANCELLED_REASON : timedOut ? OVERALL_TIMEOUT_REASON : result.error
|
|
5444
5509
|
};
|
|
5445
5510
|
}
|
|
5446
5511
|
const parsed = parseVote(result.text, question, this.refusalOptionId);
|
|
@@ -5539,9 +5604,27 @@ var CouncilOrchestrator = class {
|
|
|
5539
5604
|
signal,
|
|
5540
5605
|
usage
|
|
5541
5606
|
);
|
|
5607
|
+
if (signal.aborted) {
|
|
5608
|
+
const cancelled = question.signal?.aborted === true;
|
|
5609
|
+
const reason = cancelled ? CALL_CANCELLED_REASON : OVERALL_TIMEOUT_REASON;
|
|
5610
|
+
return resultEnvelope({
|
|
5611
|
+
status: cancelled ? "cancelled" : "failed",
|
|
5612
|
+
reason,
|
|
5613
|
+
resolution: "none",
|
|
5614
|
+
votes,
|
|
5615
|
+
profile,
|
|
5616
|
+
usage,
|
|
5617
|
+
startedAt,
|
|
5618
|
+
warnings,
|
|
5619
|
+
errors: errors.some((entry) => entry.includes(reason)) ? errors : [...errors, reason],
|
|
5620
|
+
judgeUsed: true
|
|
5621
|
+
});
|
|
5622
|
+
}
|
|
5542
5623
|
if (!judged.ok) {
|
|
5543
5624
|
return resultEnvelope({
|
|
5544
|
-
|
|
5625
|
+
// User cancel -> cancelled; overall budget expired mid-judge -> failed;
|
|
5626
|
+
// otherwise the judge simply failed -> abstained (can't decide).
|
|
5627
|
+
status: question.signal?.aborted ? "cancelled" : signal.aborted ? "failed" : "abstained",
|
|
5545
5628
|
reason: judged.error,
|
|
5546
5629
|
resolution: "none",
|
|
5547
5630
|
votes,
|
|
@@ -5601,6 +5684,19 @@ var CouncilOrchestrator = class {
|
|
|
5601
5684
|
});
|
|
5602
5685
|
}
|
|
5603
5686
|
if (!profile.judge) {
|
|
5687
|
+
if (divergentStances(valid)) {
|
|
5688
|
+
return resultEnvelope({
|
|
5689
|
+
status: "abstained",
|
|
5690
|
+
reason: "Council produced multiple distinct stances and has no judge to reconcile them.",
|
|
5691
|
+
resolution: "none",
|
|
5692
|
+
votes,
|
|
5693
|
+
profile,
|
|
5694
|
+
usage,
|
|
5695
|
+
startedAt,
|
|
5696
|
+
warnings,
|
|
5697
|
+
errors
|
|
5698
|
+
});
|
|
5699
|
+
}
|
|
5604
5700
|
const first = valid[0];
|
|
5605
5701
|
if (!first) {
|
|
5606
5702
|
return resultEnvelope({
|
|
@@ -5637,9 +5733,30 @@ var CouncilOrchestrator = class {
|
|
|
5637
5733
|
signal,
|
|
5638
5734
|
usage
|
|
5639
5735
|
);
|
|
5736
|
+
if (signal.aborted) {
|
|
5737
|
+
const cancelled = question.signal?.aborted === true;
|
|
5738
|
+
const reason = cancelled ? CALL_CANCELLED_REASON : OVERALL_TIMEOUT_REASON;
|
|
5739
|
+
return resultEnvelope({
|
|
5740
|
+
status: cancelled ? "cancelled" : "failed",
|
|
5741
|
+
reason,
|
|
5742
|
+
resolution: "none",
|
|
5743
|
+
votes,
|
|
5744
|
+
profile,
|
|
5745
|
+
usage,
|
|
5746
|
+
startedAt,
|
|
5747
|
+
warnings,
|
|
5748
|
+
errors: errors.some((entry) => entry.includes(reason)) ? errors : [...errors, reason],
|
|
5749
|
+
judgeUsed: true
|
|
5750
|
+
});
|
|
5751
|
+
}
|
|
5640
5752
|
if (!judged.ok) {
|
|
5641
5753
|
return resultEnvelope({
|
|
5642
|
-
|
|
5754
|
+
// User cancel -> cancelled; overall budget expired mid-judge -> failed;
|
|
5755
|
+
// otherwise the judge simply failed -> failed (open questions cannot
|
|
5756
|
+
// abstain for a judge failure — 'abstained' is reserved for quorum
|
|
5757
|
+
// failure and stance divergence; the option path maps this same
|
|
5758
|
+
// plain-judge-failure case to 'abstained' instead).
|
|
5759
|
+
status: question.signal?.aborted ? "cancelled" : "failed",
|
|
5643
5760
|
reason: judged.error,
|
|
5644
5761
|
resolution: "none",
|
|
5645
5762
|
votes,
|
|
@@ -5678,18 +5795,28 @@ var CouncilOrchestrator = class {
|
|
|
5678
5795
|
signal,
|
|
5679
5796
|
usage
|
|
5680
5797
|
});
|
|
5681
|
-
if (result.error)
|
|
5798
|
+
if (result.error) {
|
|
5799
|
+
if (signal.aborted && !question.signal?.aborted) {
|
|
5800
|
+
return { ok: false, error: OVERALL_TIMEOUT_REASON };
|
|
5801
|
+
}
|
|
5802
|
+
if (question.signal?.aborted) {
|
|
5803
|
+
return { ok: false, error: CALL_CANCELLED_REASON };
|
|
5804
|
+
}
|
|
5805
|
+
return { ok: false, error: result.error };
|
|
5806
|
+
}
|
|
5682
5807
|
return parseJudge(result.text, question, this.refusalOptionId);
|
|
5683
5808
|
}
|
|
5684
5809
|
/**
|
|
5685
|
-
* Resolve the effective LLM caller for a call. Voter seats
|
|
5686
|
-
* `seatCaller(seatIndex)` when wired
|
|
5687
|
-
*
|
|
5688
|
-
*
|
|
5810
|
+
* Resolve the effective LLM caller for a call. Voter seats (defined
|
|
5811
|
+
* seatIndex) use `seatCaller(seatIndex)` when wired, otherwise the shared
|
|
5812
|
+
* `caller` — a seat never falls through to the judge caller. Judge seats
|
|
5813
|
+
* (seatIndex undefined) use `judgeCaller` if set, otherwise `seatCaller(0)`
|
|
5814
|
+
* if set, otherwise the shared `caller`.
|
|
5689
5815
|
*/
|
|
5690
5816
|
resolveCaller(seatIndex) {
|
|
5691
|
-
if (seatIndex !== void 0
|
|
5692
|
-
return this.seatCaller(seatIndex);
|
|
5817
|
+
if (seatIndex !== void 0) {
|
|
5818
|
+
if (this.seatCaller) return this.seatCaller(seatIndex);
|
|
5819
|
+
return this.caller ?? this.judgeCaller;
|
|
5693
5820
|
}
|
|
5694
5821
|
if (this.judgeCaller) return this.judgeCaller;
|
|
5695
5822
|
if (this.seatCaller) return this.seatCaller(0);
|
|
@@ -5698,6 +5825,7 @@ var CouncilOrchestrator = class {
|
|
|
5698
5825
|
async safeCall(input) {
|
|
5699
5826
|
const effectiveCaller = this.resolveCaller(input.seatIndex);
|
|
5700
5827
|
const resolvedTarget = this.resolveCouncilTarget(input.target);
|
|
5828
|
+
const startedAt = Date.now();
|
|
5701
5829
|
try {
|
|
5702
5830
|
const result = await effectiveCaller.call({
|
|
5703
5831
|
system: input.system,
|
|
@@ -5714,8 +5842,17 @@ var CouncilOrchestrator = class {
|
|
|
5714
5842
|
addUsage(input.usage, result);
|
|
5715
5843
|
return result;
|
|
5716
5844
|
} catch (error) {
|
|
5717
|
-
|
|
5718
|
-
|
|
5845
|
+
const failed = {
|
|
5846
|
+
text: "",
|
|
5847
|
+
model: resolvedTarget?.model ?? "",
|
|
5848
|
+
provider: resolvedTarget?.providerId ?? "",
|
|
5849
|
+
tokens: { input: 0, output: 0, total: 0 },
|
|
5850
|
+
durationMs: Math.max(0, Date.now() - startedAt),
|
|
5851
|
+
fromFallback: false,
|
|
5852
|
+
error: errorMessage(error)
|
|
5853
|
+
};
|
|
5854
|
+
addUsage(input.usage, failed);
|
|
5855
|
+
return failed;
|
|
5719
5856
|
}
|
|
5720
5857
|
}
|
|
5721
5858
|
/**
|
|
@@ -5747,47 +5884,77 @@ var CouncilOrchestrator = class {
|
|
|
5747
5884
|
};
|
|
5748
5885
|
}
|
|
5749
5886
|
};
|
|
5750
|
-
function
|
|
5887
|
+
function parseCouncilResponse(text, question, refusalOptionId, opts) {
|
|
5888
|
+
const roleLabel = opts.role === "judge" ? "Judge" : "Voter";
|
|
5751
5889
|
const parsed = parseObject(text);
|
|
5752
5890
|
if (!parsed.ok && (!question.options || question.options.length === 0)) {
|
|
5753
5891
|
const fallback = text.trim();
|
|
5754
|
-
if (fallback) return { ok: true,
|
|
5755
|
-
return { ok: false, error:
|
|
5892
|
+
if (fallback) return { ok: true, value: { [opts.freeTextField]: fallback } };
|
|
5893
|
+
return { ok: false, error: `${roleLabel} returned an empty response.` };
|
|
5756
5894
|
}
|
|
5757
5895
|
if (!parsed.ok) return parsed;
|
|
5758
5896
|
const rationale = optionalString(parsed.value["rationale"]);
|
|
5759
5897
|
if (question.options && question.options.length > 0) {
|
|
5760
5898
|
const optionId = optionalString(parsed.value["optionId"]);
|
|
5761
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
5899
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
5900
|
+
...question.options.map((option) => option.id.trim()),
|
|
5901
|
+
refusalOptionId
|
|
5902
|
+
]);
|
|
5762
5903
|
if (!optionId || !allowed.has(optionId)) {
|
|
5763
|
-
return { ok: false, error:
|
|
5904
|
+
return { ok: false, error: `${roleLabel} returned an unknown or missing optionId.` };
|
|
5764
5905
|
}
|
|
5765
|
-
return { ok: true,
|
|
5906
|
+
return { ok: true, value: { optionId, ...rationale ? { rationale } : {} } };
|
|
5907
|
+
}
|
|
5908
|
+
const freeText = optionalString(parsed.value[opts.freeTextField]);
|
|
5909
|
+
if (!freeText) {
|
|
5910
|
+
return {
|
|
5911
|
+
ok: false,
|
|
5912
|
+
error: `${roleLabel} returned an empty or missing ${opts.freeTextField}.`
|
|
5913
|
+
};
|
|
5766
5914
|
}
|
|
5767
|
-
|
|
5768
|
-
if (!stance) return { ok: false, error: "Voter returned an empty or missing stance." };
|
|
5769
|
-
return { ok: true, vote: { stance, ...rationale ? { rationale } : {} } };
|
|
5915
|
+
return { ok: true, value: { [opts.freeTextField]: freeText, ...rationale ? { rationale } : {} } };
|
|
5770
5916
|
}
|
|
5771
|
-
function
|
|
5772
|
-
const
|
|
5773
|
-
|
|
5774
|
-
const
|
|
5775
|
-
if (
|
|
5776
|
-
|
|
5917
|
+
function divergentStances(valid) {
|
|
5918
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5919
|
+
for (const vote of valid) {
|
|
5920
|
+
const normalized = vote.stance.trim().replace(/^["'`]+|["'`]+$/g, "").toLowerCase().replace(/[.!?;:,]+$/g, "").replace(/\s+/g, " ").trim();
|
|
5921
|
+
if (!normalized) return true;
|
|
5922
|
+
seen.add(normalized);
|
|
5923
|
+
if (seen.size > 1) return true;
|
|
5777
5924
|
}
|
|
5925
|
+
return false;
|
|
5926
|
+
}
|
|
5927
|
+
function parseVote(text, question, refusalOptionId) {
|
|
5928
|
+
const parsed = parseCouncilResponse(text, question, refusalOptionId, {
|
|
5929
|
+
role: "voter",
|
|
5930
|
+
freeTextField: "stance"
|
|
5931
|
+
});
|
|
5778
5932
|
if (!parsed.ok) return parsed;
|
|
5779
|
-
const rationale =
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5933
|
+
const { optionId, stance, rationale } = parsed.value;
|
|
5934
|
+
return {
|
|
5935
|
+
ok: true,
|
|
5936
|
+
vote: {
|
|
5937
|
+
...optionId ? { optionId } : {},
|
|
5938
|
+
...stance ? { stance } : {},
|
|
5939
|
+
...rationale ? { rationale } : {}
|
|
5785
5940
|
}
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5941
|
+
};
|
|
5942
|
+
}
|
|
5943
|
+
function parseJudge(text, question, refusalOptionId) {
|
|
5944
|
+
const parsed = parseCouncilResponse(text, question, refusalOptionId, {
|
|
5945
|
+
role: "judge",
|
|
5946
|
+
freeTextField: "answer"
|
|
5947
|
+
});
|
|
5948
|
+
if (!parsed.ok) return parsed;
|
|
5949
|
+
const { optionId, answer, rationale } = parsed.value;
|
|
5950
|
+
return {
|
|
5951
|
+
ok: true,
|
|
5952
|
+
value: {
|
|
5953
|
+
...optionId ? { optionId } : {},
|
|
5954
|
+
...answer ? { answer } : {},
|
|
5955
|
+
...rationale ? { rationale } : {}
|
|
5956
|
+
}
|
|
5957
|
+
};
|
|
5791
5958
|
}
|
|
5792
5959
|
function parseObject(text) {
|
|
5793
5960
|
const trimmed = text.trim();
|
|
@@ -5831,7 +5998,7 @@ function callMetadata(result) {
|
|
|
5831
5998
|
};
|
|
5832
5999
|
}
|
|
5833
6000
|
function addUsage(usage, result) {
|
|
5834
|
-
usage.calls += 1;
|
|
6001
|
+
usage.calls += Math.max(1, result.attempts ?? 1);
|
|
5835
6002
|
usage.inputTokens += result.tokens.input;
|
|
5836
6003
|
usage.outputTokens += result.tokens.output;
|
|
5837
6004
|
usage.totalTokens += result.tokens.total;
|
|
@@ -5840,21 +6007,40 @@ function usageResult(usage, startedAt) {
|
|
|
5840
6007
|
return Object.freeze({ ...usage, durationMs: Math.max(0, Date.now() - startedAt) });
|
|
5841
6008
|
}
|
|
5842
6009
|
function cancelledVote(seat) {
|
|
5843
|
-
return {
|
|
6010
|
+
return {
|
|
6011
|
+
seatId: seat.id,
|
|
6012
|
+
persona: seat.persona,
|
|
6013
|
+
status: "cancelled",
|
|
6014
|
+
...seat.target?.providerId ? { provider: seat.target.providerId } : {},
|
|
6015
|
+
...seat.target?.model ? { model: seat.target.model } : {},
|
|
6016
|
+
durationMs: 0,
|
|
6017
|
+
error: CALL_CANCELLED_REASON
|
|
6018
|
+
};
|
|
5844
6019
|
}
|
|
5845
6020
|
function distinctTargetCount(votes, profile) {
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
6021
|
+
return new Set(distinctTargetKeys(votes, profile)).size;
|
|
6022
|
+
}
|
|
6023
|
+
function distinctTargetKeys(votes, profile) {
|
|
6024
|
+
const keys = [];
|
|
6025
|
+
for (const vote of votes) {
|
|
6026
|
+
if (vote.status !== "valid") continue;
|
|
6027
|
+
const provider = vote.provider?.trim() ?? "";
|
|
6028
|
+
const model = vote.model?.trim() ?? "";
|
|
6029
|
+
if (profile.distinctness === "provider") {
|
|
6030
|
+
if (provider) keys.push(provider);
|
|
6031
|
+
} else if (provider || model) {
|
|
6032
|
+
keys.push(`${provider}/${model}`);
|
|
6033
|
+
}
|
|
6034
|
+
}
|
|
6035
|
+
return keys;
|
|
5850
6036
|
}
|
|
5851
6037
|
function distinctnessWarnings(votes, profile) {
|
|
5852
6038
|
if (profile.distinctness === "none") return [];
|
|
5853
|
-
const
|
|
5854
|
-
const distinct =
|
|
5855
|
-
if (
|
|
6039
|
+
const keys = distinctTargetKeys(votes, profile);
|
|
6040
|
+
const distinct = new Set(keys).size;
|
|
6041
|
+
if (keys.length > 1 && distinct < keys.length) {
|
|
5856
6042
|
return [
|
|
5857
|
-
`Council distinctness policy "${profile.distinctness}" was not met: ${distinct} distinct target(s) served ${
|
|
6043
|
+
`Council distinctness policy "${profile.distinctness}" was not met: ${distinct} distinct target(s) served ${keys.length} valid vote(s).`
|
|
5858
6044
|
];
|
|
5859
6045
|
}
|
|
5860
6046
|
return [];
|
|
@@ -5890,17 +6076,6 @@ async function mapConcurrent(items, concurrency, worker) {
|
|
|
5890
6076
|
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => run()));
|
|
5891
6077
|
return results;
|
|
5892
6078
|
}
|
|
5893
|
-
function emptyCallResult(error) {
|
|
5894
|
-
return {
|
|
5895
|
-
text: "",
|
|
5896
|
-
model: "",
|
|
5897
|
-
provider: "",
|
|
5898
|
-
tokens: { input: 0, output: 0, total: 0 },
|
|
5899
|
-
durationMs: 0,
|
|
5900
|
-
fromFallback: false,
|
|
5901
|
-
error
|
|
5902
|
-
};
|
|
5903
|
-
}
|
|
5904
6079
|
function optionalString(value) {
|
|
5905
6080
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
5906
6081
|
}
|
|
@@ -5947,52 +6122,58 @@ function resolvePersonaRegistry(voters) {
|
|
|
5947
6122
|
});
|
|
5948
6123
|
return { registry, personaIds };
|
|
5949
6124
|
}
|
|
6125
|
+
function makeSeatCallerForVoter(target) {
|
|
6126
|
+
return {
|
|
6127
|
+
async call(input) {
|
|
6128
|
+
const startedAt = Date.now();
|
|
6129
|
+
try {
|
|
6130
|
+
const result = await completeBrainLlmDetailed(
|
|
6131
|
+
{ provider: target.provider, model: input.model ?? target.model },
|
|
6132
|
+
{
|
|
6133
|
+
system: typeof input.system === "string" ? input.system : Array.isArray(input.system) ? input.system.map((b) => b.text).join("\n") : "",
|
|
6134
|
+
user: input.userPrompt ?? "",
|
|
6135
|
+
timeoutMs: input.timeoutMs ?? 15e3,
|
|
6136
|
+
maxTokens: input.maxTokens,
|
|
6137
|
+
// Forward the orchestrator's signal (overall budget + caller
|
|
6138
|
+
// cancellation) so an in-flight seat call is interrupted when
|
|
6139
|
+
// the council times out or is cancelled instead of running to
|
|
6140
|
+
// its per-call timeout. Previously this was dropped and a
|
|
6141
|
+
// cancelled council waited for every seat to finish.
|
|
6142
|
+
signal: input.signal
|
|
6143
|
+
}
|
|
6144
|
+
);
|
|
6145
|
+
const inputTokens = result.usage?.input ?? 0;
|
|
6146
|
+
const outputTokens = result.usage?.output ?? 0;
|
|
6147
|
+
return {
|
|
6148
|
+
text: result.text,
|
|
6149
|
+
model: target.model,
|
|
6150
|
+
provider: target.provider.id,
|
|
6151
|
+
tokens: {
|
|
6152
|
+
input: inputTokens,
|
|
6153
|
+
output: outputTokens,
|
|
6154
|
+
total: inputTokens + outputTokens
|
|
6155
|
+
},
|
|
6156
|
+
durationMs: Date.now() - startedAt,
|
|
6157
|
+
fromFallback: false
|
|
6158
|
+
};
|
|
6159
|
+
} catch (error) {
|
|
6160
|
+
return {
|
|
6161
|
+
text: "",
|
|
6162
|
+
model: target.model,
|
|
6163
|
+
provider: target.provider.id,
|
|
6164
|
+
tokens: { input: 0, output: 0, total: 0 },
|
|
6165
|
+
durationMs: 0,
|
|
6166
|
+
fromFallback: false,
|
|
6167
|
+
error: error instanceof Error ? error.message : String(error)
|
|
6168
|
+
};
|
|
6169
|
+
}
|
|
6170
|
+
}
|
|
6171
|
+
};
|
|
6172
|
+
}
|
|
5950
6173
|
function createCouncilBrainArbiter(opts) {
|
|
5951
6174
|
if (opts.voters.length === 0) {
|
|
5952
6175
|
throw new Error("createCouncilBrainArbiter: at least one voter is required.");
|
|
5953
6176
|
}
|
|
5954
|
-
function makeSeatCallerForVoter(target) {
|
|
5955
|
-
return {
|
|
5956
|
-
async call(input) {
|
|
5957
|
-
const startedAt = Date.now();
|
|
5958
|
-
try {
|
|
5959
|
-
const result = await completeBrainLlmDetailed(
|
|
5960
|
-
{ provider: target.provider, model: input.model ?? target.model },
|
|
5961
|
-
{
|
|
5962
|
-
system: typeof input.system === "string" ? input.system : Array.isArray(input.system) ? input.system.map((b) => b.text).join("\n") : "",
|
|
5963
|
-
user: input.userPrompt ?? "",
|
|
5964
|
-
timeoutMs: input.timeoutMs ?? 15e3,
|
|
5965
|
-
maxTokens: input.maxTokens
|
|
5966
|
-
}
|
|
5967
|
-
);
|
|
5968
|
-
const inputTokens = result.usage?.input ?? 0;
|
|
5969
|
-
const outputTokens = result.usage?.output ?? 0;
|
|
5970
|
-
return {
|
|
5971
|
-
text: result.text,
|
|
5972
|
-
model: target.model,
|
|
5973
|
-
provider: target.provider.id,
|
|
5974
|
-
tokens: {
|
|
5975
|
-
input: inputTokens,
|
|
5976
|
-
output: outputTokens,
|
|
5977
|
-
total: inputTokens + outputTokens
|
|
5978
|
-
},
|
|
5979
|
-
durationMs: Date.now() - startedAt,
|
|
5980
|
-
fromFallback: false
|
|
5981
|
-
};
|
|
5982
|
-
} catch (error) {
|
|
5983
|
-
return {
|
|
5984
|
-
text: "",
|
|
5985
|
-
model: target.model,
|
|
5986
|
-
provider: target.provider.id,
|
|
5987
|
-
tokens: { input: 0, output: 0, total: 0 },
|
|
5988
|
-
durationMs: 0,
|
|
5989
|
-
fromFallback: false,
|
|
5990
|
-
error: error instanceof Error ? error.message : String(error)
|
|
5991
|
-
};
|
|
5992
|
-
}
|
|
5993
|
-
}
|
|
5994
|
-
};
|
|
5995
|
-
}
|
|
5996
6177
|
const seatCaller = (seatIndex) => {
|
|
5997
6178
|
const voter = opts.voters[seatIndex];
|
|
5998
6179
|
if (!voter) {
|
|
@@ -6030,13 +6211,23 @@ function createCouncilBrainArbiter(opts) {
|
|
|
6030
6211
|
model: opts.judge.model,
|
|
6031
6212
|
role: "judge"
|
|
6032
6213
|
} : false;
|
|
6214
|
+
const perCallTimeoutMs = opts.decisionTimeoutMs ?? 15e3;
|
|
6215
|
+
const effectiveConcurrency = Math.max(
|
|
6216
|
+
1,
|
|
6217
|
+
Math.min(opts.maxConcurrency ?? DEFAULT_COUNCIL_MAX_CONCURRENCY, seats.length)
|
|
6218
|
+
);
|
|
6219
|
+
const overallTimeoutMs = Math.max(
|
|
6220
|
+
DEFAULT_COUNCIL_OVERALL_TIMEOUT_MS,
|
|
6221
|
+
perCallTimeoutMs * (Math.ceil(seats.length / effectiveConcurrency) + 1)
|
|
6222
|
+
);
|
|
6033
6223
|
const profile = {
|
|
6034
6224
|
id: "brain-council-adapter",
|
|
6035
6225
|
seats,
|
|
6036
6226
|
judge: judgeTarget,
|
|
6037
6227
|
quorumFraction: opts.quorumFraction ?? 0.5,
|
|
6038
6228
|
approvalFraction: opts.approvalFraction ?? 0.5,
|
|
6039
|
-
perCallTimeoutMs
|
|
6229
|
+
perCallTimeoutMs,
|
|
6230
|
+
overallTimeoutMs,
|
|
6040
6231
|
...opts.judgeMaxTokens !== void 0 ? { judgeMaxTokens: opts.judgeMaxTokens } : {},
|
|
6041
6232
|
distinctness: opts.distinctness ?? "none"
|
|
6042
6233
|
};
|
|
@@ -15965,8 +16156,17 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
15965
16156
|
durationMs: 0
|
|
15966
16157
|
};
|
|
15967
16158
|
this.completedResults.push(synthetic);
|
|
16159
|
+
this.trimCompletedResults();
|
|
15968
16160
|
this.emit("task.completed", { task, result: synthetic });
|
|
15969
16161
|
}
|
|
16162
|
+
trimCompletedResults() {
|
|
16163
|
+
if (this.completedResults.length > _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS) {
|
|
16164
|
+
this.completedResults.splice(
|
|
16165
|
+
0,
|
|
16166
|
+
this.completedResults.length - _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS
|
|
16167
|
+
);
|
|
16168
|
+
}
|
|
16169
|
+
}
|
|
15970
16170
|
async runDispatched(subagentId, task) {
|
|
15971
16171
|
const subagent = this.subagents.get(subagentId);
|
|
15972
16172
|
if (!subagent) return;
|
|
@@ -16100,12 +16300,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
16100
16300
|
}
|
|
16101
16301
|
recordCompletion(result) {
|
|
16102
16302
|
this.completedResults.push(result);
|
|
16103
|
-
|
|
16104
|
-
this.completedResults.splice(
|
|
16105
|
-
0,
|
|
16106
|
-
this.completedResults.length - _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS
|
|
16107
|
-
);
|
|
16108
|
-
}
|
|
16303
|
+
this.trimCompletedResults();
|
|
16109
16304
|
this.totalIterations += result.iterations;
|
|
16110
16305
|
if (this.inFlight > 0) {
|
|
16111
16306
|
this.inFlight--;
|
|
@@ -20411,6 +20606,7 @@ var OneShotOrchestrator = class {
|
|
|
20411
20606
|
tokens: { input: 0, output: 0, total: 0 },
|
|
20412
20607
|
durationMs: Math.round(performance.now() - startedAt),
|
|
20413
20608
|
fromFallback: false,
|
|
20609
|
+
attempts: 0,
|
|
20414
20610
|
error: "No provider or model could be resolved. Check your config."
|
|
20415
20611
|
};
|
|
20416
20612
|
}
|
|
@@ -20425,6 +20621,7 @@ var OneShotOrchestrator = class {
|
|
|
20425
20621
|
tokens: { input: 0, output: 0, total: 0 },
|
|
20426
20622
|
durationMs: Math.round(performance.now() - startedAt),
|
|
20427
20623
|
fromFallback: false,
|
|
20624
|
+
attempts: 0,
|
|
20428
20625
|
error: `Cannot build provider "${target.providerId}": ${err instanceof Error ? err.message : String(err)}`
|
|
20429
20626
|
};
|
|
20430
20627
|
}
|
|
@@ -20437,11 +20634,13 @@ var OneShotOrchestrator = class {
|
|
|
20437
20634
|
let fromFallback = false;
|
|
20438
20635
|
let lastError;
|
|
20439
20636
|
let fallbackEligible = false;
|
|
20637
|
+
let attempts = 0;
|
|
20440
20638
|
if (tracker && !tracker.isAvailable(target.providerId, target.model) || !evaluateModelCalendar(config.modelAvailabilitySchedule, target.providerId, target.model).allowed) {
|
|
20441
20639
|
this.opts.logger?.debug(
|
|
20442
20640
|
`one-shot: primary "${target.providerId}/${target.model}" is blocked \u2014 trying fallback`
|
|
20443
20641
|
);
|
|
20444
20642
|
} else {
|
|
20643
|
+
attempts += 1;
|
|
20445
20644
|
const primaryAttempt = await this.tryCall(
|
|
20446
20645
|
provider,
|
|
20447
20646
|
request,
|
|
@@ -20456,10 +20655,17 @@ var OneShotOrchestrator = class {
|
|
|
20456
20655
|
tracker?.recordSuccess(target.providerId, target.model);
|
|
20457
20656
|
servingProviderId = provider.id;
|
|
20458
20657
|
servingModel = target.model;
|
|
20459
|
-
return this.buildResult(result, servingProviderId, servingModel, false, startedAt);
|
|
20658
|
+
return this.buildResult(result, servingProviderId, servingModel, false, startedAt, attempts);
|
|
20460
20659
|
}
|
|
20461
20660
|
if (!fallbackEligible || chain.length === 0) {
|
|
20462
|
-
return this.buildErrorResult(
|
|
20661
|
+
return this.buildErrorResult(
|
|
20662
|
+
lastError,
|
|
20663
|
+
target.providerId,
|
|
20664
|
+
target.model,
|
|
20665
|
+
false,
|
|
20666
|
+
startedAt,
|
|
20667
|
+
attempts
|
|
20668
|
+
);
|
|
20463
20669
|
}
|
|
20464
20670
|
}
|
|
20465
20671
|
const estimatedTokens = estimateRequestTokens(request.messages, request.system, []).total;
|
|
@@ -20487,6 +20693,7 @@ var OneShotOrchestrator = class {
|
|
|
20487
20693
|
}
|
|
20488
20694
|
servingProviderId = fbProvider.id;
|
|
20489
20695
|
servingModel = entry.model;
|
|
20696
|
+
attempts += 1;
|
|
20490
20697
|
const attempt = await this.tryCall(
|
|
20491
20698
|
fbProvider,
|
|
20492
20699
|
this.buildRequest(input, entry.model),
|
|
@@ -20497,7 +20704,14 @@ var OneShotOrchestrator = class {
|
|
|
20497
20704
|
if (attempt.response) {
|
|
20498
20705
|
tracker?.recordSuccess(entry.providerId, entry.model);
|
|
20499
20706
|
fromFallback = true;
|
|
20500
|
-
return this.buildResult(
|
|
20707
|
+
return this.buildResult(
|
|
20708
|
+
attempt.response,
|
|
20709
|
+
servingProviderId,
|
|
20710
|
+
servingModel,
|
|
20711
|
+
true,
|
|
20712
|
+
startedAt,
|
|
20713
|
+
attempts
|
|
20714
|
+
);
|
|
20501
20715
|
}
|
|
20502
20716
|
lastError = attempt.error;
|
|
20503
20717
|
}
|
|
@@ -20506,7 +20720,8 @@ var OneShotOrchestrator = class {
|
|
|
20506
20720
|
servingProviderId,
|
|
20507
20721
|
servingModel,
|
|
20508
20722
|
fromFallback,
|
|
20509
|
-
startedAt
|
|
20723
|
+
startedAt,
|
|
20724
|
+
attempts
|
|
20510
20725
|
);
|
|
20511
20726
|
}
|
|
20512
20727
|
// ── Private helpers ─────────────────────────────────────────────
|
|
@@ -20630,7 +20845,7 @@ var OneShotOrchestrator = class {
|
|
|
20630
20845
|
}
|
|
20631
20846
|
}
|
|
20632
20847
|
/** Build a success result from a provider Response. */
|
|
20633
|
-
buildResult(response, servingProviderId, servingModel, fromFallback, startedAt) {
|
|
20848
|
+
buildResult(response, servingProviderId, servingModel, fromFallback, startedAt, attempts) {
|
|
20634
20849
|
const textBlocks = response.content.filter(isTextBlock);
|
|
20635
20850
|
const text = textBlocks.map((b) => b.text).join("\n").trim();
|
|
20636
20851
|
return {
|
|
@@ -20644,11 +20859,12 @@ var OneShotOrchestrator = class {
|
|
|
20644
20859
|
},
|
|
20645
20860
|
durationMs: Math.round(performance.now() - startedAt),
|
|
20646
20861
|
fromFallback,
|
|
20862
|
+
attempts,
|
|
20647
20863
|
stopReason: response.stopReason
|
|
20648
20864
|
};
|
|
20649
20865
|
}
|
|
20650
20866
|
/** Build a total-failure error result. */
|
|
20651
|
-
buildErrorResult(error, servingProviderId, servingModel, fromFallback, startedAt) {
|
|
20867
|
+
buildErrorResult(error, servingProviderId, servingModel, fromFallback, startedAt, attempts) {
|
|
20652
20868
|
return {
|
|
20653
20869
|
text: "",
|
|
20654
20870
|
model: servingModel,
|
|
@@ -20656,6 +20872,7 @@ var OneShotOrchestrator = class {
|
|
|
20656
20872
|
tokens: { input: 0, output: 0, total: 0 },
|
|
20657
20873
|
durationMs: Math.round(performance.now() - startedAt),
|
|
20658
20874
|
fromFallback,
|
|
20875
|
+
attempts,
|
|
20659
20876
|
error: error instanceof Error ? error.message : String(error ?? "Unknown error")
|
|
20660
20877
|
};
|
|
20661
20878
|
}
|