@bivy/bivy 0.15.0-staging.50 → 0.15.0-staging.52
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/control-plane-tasks.js +11 -1
- package/dist/policy/ruleset.js +19 -2
- package/dist/server.js +48 -1
- package/package.json +1 -1
|
@@ -386,7 +386,17 @@ export class ControlPlaneTaskPoller {
|
|
|
386
386
|
],
|
|
387
387
|
});
|
|
388
388
|
if (decision.action === "reroute") {
|
|
389
|
-
|
|
389
|
+
// A candidate changes only the routing dimensions it names. Preserve
|
|
390
|
+
// the existing runtime/model for partial fallback routes (for example
|
|
391
|
+
// a model-only fallback must not silently reset the selected agent).
|
|
392
|
+
current = {
|
|
393
|
+
...current,
|
|
394
|
+
...(decision.routing.runtimeId !== undefined ? { runtimeId: decision.routing.runtimeId } : {}),
|
|
395
|
+
...(decision.routing.model !== undefined ? { model: decision.routing.model } : {}),
|
|
396
|
+
// Account routing is not yet represented by WorkItem. Do not claim
|
|
397
|
+
// that an account fallback was applied until the queue wire shape
|
|
398
|
+
// and credential resolver support it end-to-end.
|
|
399
|
+
};
|
|
390
400
|
rerouteCount = decision.rerouteCount;
|
|
391
401
|
await report({ routingReason: `fallback: ${decision.ref}` });
|
|
392
402
|
}
|
package/dist/policy/ruleset.js
CHANGED
|
@@ -94,8 +94,25 @@ export const DEFAULT_RULESET = {
|
|
|
94
94
|
* human-readable errors — never throws.
|
|
95
95
|
*/
|
|
96
96
|
export function validateRuleset(value) {
|
|
97
|
-
if (Check(RulesetSchema, value))
|
|
98
|
-
|
|
97
|
+
if (Check(RulesetSchema, value)) {
|
|
98
|
+
const ruleset = value;
|
|
99
|
+
const errors = [];
|
|
100
|
+
for (let ruleIndex = 0; ruleIndex < ruleset.rules.length; ruleIndex += 1) {
|
|
101
|
+
const rule = ruleset.rules[ruleIndex];
|
|
102
|
+
if (rule.action !== "reroute" || !rule.chain)
|
|
103
|
+
continue;
|
|
104
|
+
for (let candidateIndex = 0; candidateIndex < rule.chain.length; candidateIndex += 1) {
|
|
105
|
+
const candidate = rule.chain[candidateIndex];
|
|
106
|
+
const hasRoute = [candidate.runtimeId, candidate.model, candidate.account]
|
|
107
|
+
.some((field) => typeof field === "string" && field.trim().length > 0);
|
|
108
|
+
if (!hasRoute)
|
|
109
|
+
errors.push(`/rules/${ruleIndex}/chain/${candidateIndex}: fallback candidate must specify runtimeId, model, or account`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (errors.length)
|
|
113
|
+
return { ok: false, errors };
|
|
114
|
+
return { ok: true, ruleset, errors: [] };
|
|
115
|
+
}
|
|
99
116
|
const errors = [...Errors(RulesetSchema, value)]
|
|
100
117
|
.slice(0, 20)
|
|
101
118
|
.map((e) => `${e.path || "/"}: ${e.message}`);
|
package/dist/server.js
CHANGED
|
@@ -4592,11 +4592,58 @@ async function reconcileInterruptedSessions() {
|
|
|
4592
4592
|
}
|
|
4593
4593
|
}
|
|
4594
4594
|
}
|
|
4595
|
+
/** Run the legacy direct GitHub queue through the same failure policy as the
|
|
4596
|
+
* hosted queue. There is no control-plane run/evidence endpoint on this path,
|
|
4597
|
+
* so the policy is applied locally and terminal failures retain the poller's
|
|
4598
|
+
* existing logging behavior. */
|
|
4599
|
+
async function runDirectGitHubIssueWithPolicy(cfg, issue) {
|
|
4600
|
+
let ruleset;
|
|
4601
|
+
try {
|
|
4602
|
+
// Repository policy has precedence, matching the hosted queue. An invalid
|
|
4603
|
+
// project policy must not disable the direct poller; fall back to the
|
|
4604
|
+
// node-global policy and leave the validation error visible in the log.
|
|
4605
|
+
ruleset = loadProjectPolicy(cfg.repoDir)?.ruleset;
|
|
4606
|
+
}
|
|
4607
|
+
catch (error) {
|
|
4608
|
+
console.warn(`[policy] ${error instanceof Error ? error.message : String(error)}`);
|
|
4609
|
+
}
|
|
4610
|
+
const policy = createRunPolicy({
|
|
4611
|
+
context: "queue",
|
|
4612
|
+
ruleset: ruleset ?? activeRulesetFor(rulesetsDir, "queue"),
|
|
4613
|
+
});
|
|
4614
|
+
let attempt = 1;
|
|
4615
|
+
let rerouteCount = 0;
|
|
4616
|
+
let routing = {};
|
|
4617
|
+
for (;;) {
|
|
4618
|
+
try {
|
|
4619
|
+
await runIssueTask(cfg, issue, { ...routing });
|
|
4620
|
+
return;
|
|
4621
|
+
}
|
|
4622
|
+
catch (error) {
|
|
4623
|
+
const decision = policy.decide({ routing, error, attempt, rerouteCount });
|
|
4624
|
+
if (decision.action !== "retry" && decision.action !== "reroute")
|
|
4625
|
+
throw error;
|
|
4626
|
+
attempt += 1;
|
|
4627
|
+
if (decision.action === "reroute") {
|
|
4628
|
+
routing = {
|
|
4629
|
+
...(routing.runtimeId !== undefined ? { runtimeId: routing.runtimeId } : {}),
|
|
4630
|
+
...(routing.model !== undefined ? { model: routing.model } : {}),
|
|
4631
|
+
...(decision.routing.runtimeId !== undefined ? { runtimeId: decision.routing.runtimeId } : {}),
|
|
4632
|
+
...(decision.routing.model !== undefined ? { model: decision.routing.model } : {}),
|
|
4633
|
+
};
|
|
4634
|
+
rerouteCount = decision.rerouteCount;
|
|
4635
|
+
}
|
|
4636
|
+
console.warn(`[github-tasks] issue #${issue.number} ${decision.action} (${decision.condition}): ${decision.summary}`);
|
|
4637
|
+
if (decision.delayMs > 0)
|
|
4638
|
+
await new Promise((resolve) => setTimeout(resolve, decision.delayMs));
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
}
|
|
4595
4642
|
async function startGitHubTasksIfConfigured() {
|
|
4596
4643
|
const cfg = await resolveGitHubTaskConfig();
|
|
4597
4644
|
if (!cfg)
|
|
4598
4645
|
return;
|
|
4599
|
-
githubPoller = new GitHubTaskPoller(cfg, (issue) =>
|
|
4646
|
+
githubPoller = new GitHubTaskPoller(cfg, (issue) => runDirectGitHubIssueWithPolicy(cfg, issue), nodeGithubMaxConcurrent);
|
|
4600
4647
|
githubPoller.start();
|
|
4601
4648
|
}
|
|
4602
4649
|
let controlPlanePoller;
|
package/package.json
CHANGED