@coreplane/switchboard 1.260.4 → 1.260.5
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/assets/deploy/cloudflare/package.json +2 -2
- package/dist/assets/deploy/cloudflare-docs/package.json +1 -1
- package/dist/assets/deploy/cloudflare-memory/package.json +2 -2
- package/dist/assets/deploy/cloudflare-memory/worker.ts +205 -8
- package/dist/assets/deploy/cloudflare-resident/package.json +2 -2
- package/dist/assets/deploy/cloudflare-resident/worker.ts +124 -40
- package/dist/assets/deploy/cloudflare-sandbox/package.json +2 -2
- package/dist/assets/package-lock.json +712 -97
- package/dist/assets/package.json +4 -4
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/core/budgets.ts +5 -0
- package/dist/assets/src/core/coordinator/contract.ts +5 -0
- package/dist/assets/src/core/coordinator/driver.ts +114 -25
- package/dist/assets/src/core/pipelineStanding.ts +2 -0
- package/dist/assets/src/core/plane/decide.ts +19 -2
- package/dist/assets/src/core/provider.ts +380 -0
- package/dist/assets/src/core/refusal.ts +1 -0
- package/dist/assets/src/core/runEvents.ts +8 -0
- package/dist/assets/src/core/runLedger/types.ts +10 -1
- package/dist/assets/src/core/runRecord.ts +31 -0
- package/dist/assets/src/core/ship/contract.ts +2 -0
- package/dist/assets/src/core/ship/coordinator.ts +487 -25
- package/dist/assets/src/core/types.ts +6 -0
- package/dist/assets/src/execution/residentRebind.ts +15 -0
- package/dist/assets/src/execution/residentReuse.ts +23 -2
- package/dist/assets/web/dist/.vite/manifest.json +67 -67
- package/dist/assets/web/dist/assets/{DeliveryPage-BaemWKW8.js → DeliveryPage-Cf1joUyA.js} +1 -1
- package/dist/assets/web/dist/assets/{HomePage-fgKQHLaO.js → HomePage-DZEAnCCv.js} +1 -1
- package/dist/assets/web/dist/assets/{PendingTurnRow-vuWiDzvz.js → PendingTurnRow-4B8JwETU.js} +1 -1
- package/dist/assets/web/dist/assets/{PlanePage-DXMJf8FB.js → PlanePage-CHU2szQs.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentDetailPage-DdC8yU_S.js → ResidentDetailPage-L5SRcN_O.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-CSM-KODv.js → ResidentsIndexPage-BIFf8qyE.js} +1 -1
- package/dist/assets/web/dist/assets/RunFoldRow-DzPIshJx.js +1 -0
- package/dist/assets/web/dist/assets/{RunRoutePage-jo6NZxsP.js → RunRoutePage-Cru5IVux.js} +3 -3
- package/dist/assets/web/dist/assets/{RunsIndexPage-Dx1Y4sSq.js → RunsIndexPage-CBkdPAdj.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-BuB_NZyR.js → ScheduledPage-D_R55BDk.js} +1 -1
- package/dist/assets/web/dist/assets/{SettingsPage-Cn96jB6Q.js → SettingsPage-DlmZvAvf.js} +1 -1
- package/dist/assets/web/dist/assets/{SilentTurn-D2cJfpEq.js → SilentTurn-PWMDMbMG.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-DDHUCPVJ.js → StatusDot-Bq0mYMFo.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-B4VIHkAI.js → Tooltip-Bs6zd7yE.js} +1 -1
- package/dist/assets/web/dist/assets/{UnitRoutePage-C-2DfjLI.js → UnitRoutePage-BMGEZCvn.js} +1 -1
- package/dist/assets/web/dist/assets/budgets-0szUBIMv.js +1 -0
- package/dist/assets/web/dist/assets/{dist-Cf1CmCSK.js → dist-EkKVbIM-.js} +11 -11
- package/dist/assets/web/dist/assets/{indexRow-Dxg7C8s9.js → indexRow-5s3hNzZ9.js} +1 -1
- package/dist/assets/web/dist/assets/{main-DxPqaFu9.js → main-Disot0n_.js} +2 -2
- package/dist/assets/web/dist/assets/{sseReplay-BzoeVxZB.js → sseReplay-9gcMpylx.js} +1 -1
- package/dist/cli.js +1855 -401
- package/package.json +4 -4
- package/dist/assets/web/dist/assets/RunFoldRow-Csik3wD6.js +0 -1
- package/dist/assets/web/dist/assets/budgets-KNNkT4PZ.js +0 -1
package/dist/cli.js
CHANGED
|
@@ -597,7 +597,7 @@ function fit(pipeline) {
|
|
|
597
597
|
const need = ALLOWANCES.provision + ASKS.coding + reserveMinutes({ kind: "coding", index: 0 }, pipeline);
|
|
598
598
|
return { ok: pipeline.maxMinutes >= need, need, have: pipeline.maxMinutes };
|
|
599
599
|
}
|
|
600
|
-
var SECOND_MS, secondsToMs, MINUTE_MS, minutesToMs, DAY_MS, WEEK_MS, CONFIRMATION_TTL_MS, QUESTION_TTL_MS, AUTHOR_BINDING_TTL_MS, FIRST_ATTACH_WAIT_MS, ATTACH_REQUEST_MIN_MS, HARNESS_PROBE_WAIT_MS, DRAIN, INTAKE_WINDOW_MAX_MS, INTAKE_RECOVERY_WINDOW_MS, LOOP_PRESETS, ASKS, PRESET_FLOORS, FLOORS, PULL_SWEEP, PROVIDER_RETRY_BACKOFFS_MS, MODEL_STREAM_HEARTBEAT_MS, HOSTED_DEADLINE_MARGIN_MINUTES, SHIP_WAIT, RESTART_CLAIM_GRACE_MS, PLANE, PACE_WINDOW_MINUTES, ALLOWANCES, POST_STEP_MINUTES, WRAP_UP_WARNING, SANDBOX_CREDENTIAL_WRITE_TIMEOUT_MS, BASH_COMMAND, RUNAWAY_TURNS_PER_MINUTE, DEFAULT_GRANT, GRANT_RENEWALS_MAX, STRUCTURED_RETRIES_MAX, IDLE_DAYS_DEFAULT, IDLE_DAYS_MAX, IDLE_WAKES_MAX;
|
|
600
|
+
var SECOND_MS, secondsToMs, MINUTE_MS, minutesToMs, DAY_MS, WEEK_MS, CONFIRMATION_TTL_MS, QUESTION_TTL_MS, AUTHOR_BINDING_TTL_MS, FIRST_ATTACH_WAIT_MS, ATTACH_REQUEST_MIN_MS, HARNESS_PROBE_WAIT_MS, DRAIN, INTAKE_WINDOW_MAX_MS, INTAKE_RECOVERY_WINDOW_MS, INTAKE_DELIVERY_CLAIM_MS, LOOP_PRESETS, ASKS, PRESET_FLOORS, FLOORS, PULL_SWEEP, PROVIDER_RETRY_BACKOFFS_MS, MODEL_STREAM_HEARTBEAT_MS, HOSTED_DEADLINE_MARGIN_MINUTES, SHIP_WAIT, RESTART_CLAIM_GRACE_MS, PLANE, PACE_WINDOW_MINUTES, ALLOWANCES, POST_STEP_MINUTES, WRAP_UP_WARNING, SANDBOX_CREDENTIAL_WRITE_TIMEOUT_MS, BASH_COMMAND, RUNAWAY_TURNS_PER_MINUTE, DEFAULT_GRANT, GRANT_RENEWALS_MAX, STRUCTURED_RETRIES_MAX, IDLE_DAYS_DEFAULT, IDLE_DAYS_MAX, IDLE_WAKES_MAX;
|
|
601
601
|
var init_budgets = __esm({
|
|
602
602
|
"../../src/core/budgets.ts"() {
|
|
603
603
|
"use strict";
|
|
@@ -633,6 +633,7 @@ var init_budgets = __esm({
|
|
|
633
633
|
};
|
|
634
634
|
INTAKE_WINDOW_MAX_MS = 30 * DAY_MS;
|
|
635
635
|
INTAKE_RECOVERY_WINDOW_MS = 10 * MINUTE_MS;
|
|
636
|
+
INTAKE_DELIVERY_CLAIM_MS = 5 * MINUTE_MS;
|
|
636
637
|
LOOP_PRESETS = [
|
|
637
638
|
"general",
|
|
638
639
|
"coding",
|
|
@@ -1648,13 +1649,13 @@ var init_configDocument = __esm({
|
|
|
1648
1649
|
describe() {
|
|
1649
1650
|
return `state Worker ${this.baseUrl}`;
|
|
1650
1651
|
}
|
|
1651
|
-
async post(path,
|
|
1652
|
+
async post(path, payload2) {
|
|
1652
1653
|
let res;
|
|
1653
1654
|
try {
|
|
1654
1655
|
res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
1655
1656
|
method: "POST",
|
|
1656
1657
|
headers: { authorization: `Bearer ${this.opts.token}`, "content-type": "application/json" },
|
|
1657
|
-
body: JSON.stringify(
|
|
1658
|
+
body: JSON.stringify(payload2),
|
|
1658
1659
|
signal: AbortSignal.timeout(this.timeoutMs)
|
|
1659
1660
|
});
|
|
1660
1661
|
} catch (err2) {
|
|
@@ -2821,6 +2822,230 @@ var init_effort = __esm({
|
|
|
2821
2822
|
});
|
|
2822
2823
|
|
|
2823
2824
|
// ../../src/core/provider.ts
|
|
2825
|
+
function providerFailureDiagnostic(cause, details2) {
|
|
2826
|
+
if (details2.provider !== void 0 && details2.keyVariable !== void 0) {
|
|
2827
|
+
if (cause === "key-absent") return `Provider "${details2.provider}": ${details2.keyVariable} is not set`;
|
|
2828
|
+
if (cause === "key-invalid") return `Provider "${details2.provider}": ${details2.keyVariable} was refused`;
|
|
2829
|
+
}
|
|
2830
|
+
return renderProviderFailure(cause);
|
|
2831
|
+
}
|
|
2832
|
+
function renderProviderFailure(cause, surface = "ended") {
|
|
2833
|
+
switch (cause) {
|
|
2834
|
+
case "transient":
|
|
2835
|
+
return surface === "parked" ? "The model provider is temporarily unavailable; your work is kept and will continue when service recovers." : "The model provider is temporarily unavailable; this request did not start.";
|
|
2836
|
+
case "rate-limited":
|
|
2837
|
+
return surface === "parked" ? "The model provider is rate-limited; your work is kept and will continue when capacity returns." : "The model provider is rate-limited; this request did not start.";
|
|
2838
|
+
case "credit-or-quota-exhausted":
|
|
2839
|
+
return surface === "parked" ? "The model provider's credit or quota is exhausted; your work is kept and will continue when service recovers." : "The model provider's credit or quota is exhausted; this request did not start.";
|
|
2840
|
+
case "key-absent":
|
|
2841
|
+
return "The model provider key is not configured; this request cannot start until the service is restored.";
|
|
2842
|
+
case "key-invalid":
|
|
2843
|
+
return "The model provider key was refused; this request cannot start until the service is restored.";
|
|
2844
|
+
case "model-unknown":
|
|
2845
|
+
return "The configured model is unavailable from its provider; this request cannot start until the service is restored.";
|
|
2846
|
+
case "request-rejected":
|
|
2847
|
+
return "The model provider rejected the request shape; no work was started.";
|
|
2848
|
+
case "permanent":
|
|
2849
|
+
return "The model provider refused the call; the request ended without exposing the provider's response.";
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
function providerSchemaRejectionRecord(value) {
|
|
2853
|
+
const row2 = providerFailureRecord(value);
|
|
2854
|
+
return typeof row2?.tool === "string" && row2.tool.length > 0 && typeof row2.keyword === "string" && row2.keyword.length > 0 ? { tool: row2.tool, keyword: row2.keyword } : void 0;
|
|
2855
|
+
}
|
|
2856
|
+
function providerFailureBody(body) {
|
|
2857
|
+
if (typeof body !== "string") return body;
|
|
2858
|
+
const text = body.trim();
|
|
2859
|
+
try {
|
|
2860
|
+
return JSON.parse(text);
|
|
2861
|
+
} catch {
|
|
2862
|
+
const at = text.indexOf("{");
|
|
2863
|
+
if (at < 0) return void 0;
|
|
2864
|
+
try {
|
|
2865
|
+
return JSON.parse(text.slice(at));
|
|
2866
|
+
} catch {
|
|
2867
|
+
return void 0;
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
function providerFailureSignals(value, into = []) {
|
|
2872
|
+
if (Array.isArray(value)) {
|
|
2873
|
+
for (const item of value) providerFailureSignals(item, into);
|
|
2874
|
+
return into;
|
|
2875
|
+
}
|
|
2876
|
+
const row2 = providerFailureRecord(value);
|
|
2877
|
+
if (!row2) return into;
|
|
2878
|
+
for (const [key, item] of Object.entries(row2)) {
|
|
2879
|
+
const normalizedKey = key.toLowerCase();
|
|
2880
|
+
if (typeof item === "string" && ["code", "type", "error_type", "reason", "limit_source"].includes(normalizedKey))
|
|
2881
|
+
into.push(item.toLowerCase());
|
|
2882
|
+
else if (typeof item === "number" && normalizedKey === "code") into.push(String(item));
|
|
2883
|
+
providerFailureSignals(item, into);
|
|
2884
|
+
}
|
|
2885
|
+
return into;
|
|
2886
|
+
}
|
|
2887
|
+
function providerFailureStatus(input, text) {
|
|
2888
|
+
if (input.status !== void 0) return input.status;
|
|
2889
|
+
const match = /(?:^|\b(?:http|status(?: code)?|error|api error)[^0-9]{0,8})([1-5]\d\d)\b/i.exec(text);
|
|
2890
|
+
return match ? Number(match[1]) : void 0;
|
|
2891
|
+
}
|
|
2892
|
+
function providerFailureText(input) {
|
|
2893
|
+
const error = input.error;
|
|
2894
|
+
if (error instanceof Error) return error.message;
|
|
2895
|
+
if (typeof error === "string") return error;
|
|
2896
|
+
if (typeof input.body === "string") return input.body;
|
|
2897
|
+
try {
|
|
2898
|
+
return input.body === void 0 ? "" : JSON.stringify(input.body);
|
|
2899
|
+
} catch {
|
|
2900
|
+
return "";
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
function quotedWord(text, word) {
|
|
2904
|
+
return [`'${word}'`, `"${word}"`, `\`${word}\``].some((candidate) => text.includes(candidate));
|
|
2905
|
+
}
|
|
2906
|
+
function toolSchemaKeywords(value, into = /* @__PURE__ */ new Set()) {
|
|
2907
|
+
if (Array.isArray(value)) {
|
|
2908
|
+
for (const item of value) toolSchemaKeywords(item, into);
|
|
2909
|
+
return into;
|
|
2910
|
+
}
|
|
2911
|
+
const schema = providerFailureRecord(value);
|
|
2912
|
+
if (!schema) return into;
|
|
2913
|
+
for (const [keyword, item] of Object.entries(schema)) {
|
|
2914
|
+
into.add(keyword);
|
|
2915
|
+
if ((keyword === "properties" || keyword === "$defs" || keyword === "definitions") && providerFailureRecord(item)) {
|
|
2916
|
+
for (const child of Object.values(providerFailureRecord(item))) toolSchemaKeywords(child, into);
|
|
2917
|
+
} else {
|
|
2918
|
+
toolSchemaKeywords(item, into);
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
return into;
|
|
2922
|
+
}
|
|
2923
|
+
function providerSchemaRejectionOf(error, tools) {
|
|
2924
|
+
if (!tools || tools.length === 0) return void 0;
|
|
2925
|
+
const text = providerFailureText({ error });
|
|
2926
|
+
const parsed = providerFailureBody(providerFailureRecord(error) ?? text);
|
|
2927
|
+
const prose2 = providerFailureProse(parsed ?? text);
|
|
2928
|
+
if (!/(?:invalid|unsupported|refused|rejected)[^.!?]{0,80}(?:json )?schema|(?:json )?schema[^.!?]{0,80}(?:invalid|unsupported|not (?:permitted|supported))/i.test(
|
|
2929
|
+
prose2
|
|
2930
|
+
))
|
|
2931
|
+
return void 0;
|
|
2932
|
+
const namedTools = tools.filter((tool2) => quotedWord(prose2, tool2.name));
|
|
2933
|
+
if (namedTools.length !== 1) return void 0;
|
|
2934
|
+
const [tool] = namedTools;
|
|
2935
|
+
const namedKeywords = [...toolSchemaKeywords(tool.inputSchema)].filter((keyword) => quotedWord(prose2, keyword));
|
|
2936
|
+
if (namedKeywords.length !== 1) return void 0;
|
|
2937
|
+
return { tool: tool.name, keyword: namedKeywords[0] };
|
|
2938
|
+
}
|
|
2939
|
+
function providerFailureProse(value, into = []) {
|
|
2940
|
+
if (typeof value === "string") {
|
|
2941
|
+
into.push(value);
|
|
2942
|
+
return into.join(" ");
|
|
2943
|
+
}
|
|
2944
|
+
if (Array.isArray(value)) {
|
|
2945
|
+
for (const item of value) providerFailureProse(item, into);
|
|
2946
|
+
return into.join(" ");
|
|
2947
|
+
}
|
|
2948
|
+
const row2 = providerFailureRecord(value);
|
|
2949
|
+
if (!row2) return into.join(" ");
|
|
2950
|
+
for (const [key, item] of Object.entries(row2)) {
|
|
2951
|
+
if (key.toLowerCase() !== "cause") providerFailureProse(item, into);
|
|
2952
|
+
}
|
|
2953
|
+
return into.join(" ");
|
|
2954
|
+
}
|
|
2955
|
+
function signalIncludes(signals, words) {
|
|
2956
|
+
return signals.some((signal2) => words.some((word) => signal2 === word || signal2.includes(word)));
|
|
2957
|
+
}
|
|
2958
|
+
function isProviderFailureCause(value) {
|
|
2959
|
+
return typeof value === "string" && PROVIDER_FAILURE_CAUSES.includes(value);
|
|
2960
|
+
}
|
|
2961
|
+
function trustedProviderFailureEnvelope(value) {
|
|
2962
|
+
if (Array.isArray(value)) {
|
|
2963
|
+
for (const item of value) {
|
|
2964
|
+
const envelope = trustedProviderFailureEnvelope(item);
|
|
2965
|
+
if (envelope !== void 0) return envelope;
|
|
2966
|
+
}
|
|
2967
|
+
return void 0;
|
|
2968
|
+
}
|
|
2969
|
+
const row2 = providerFailureRecord(value);
|
|
2970
|
+
if (!row2) return void 0;
|
|
2971
|
+
if (row2.type === "provider_failure" && isProviderFailureCause(row2.cause)) {
|
|
2972
|
+
const schemaRejection = providerSchemaRejectionRecord(row2.schemaRejection);
|
|
2973
|
+
return { cause: row2.cause, ...schemaRejection !== void 0 ? { schemaRejection } : {} };
|
|
2974
|
+
}
|
|
2975
|
+
for (const item of Object.values(row2)) {
|
|
2976
|
+
const envelope = trustedProviderFailureEnvelope(item);
|
|
2977
|
+
if (envelope !== void 0) return envelope;
|
|
2978
|
+
}
|
|
2979
|
+
return void 0;
|
|
2980
|
+
}
|
|
2981
|
+
function classifyProviderFailure(input) {
|
|
2982
|
+
if (input.error instanceof ProviderFailure) return input.error;
|
|
2983
|
+
const text = providerFailureText(input);
|
|
2984
|
+
const parsed = providerFailureBody(input.body ?? providerFailureRecord(input.error) ?? text);
|
|
2985
|
+
const signals = providerFailureSignals(parsed);
|
|
2986
|
+
const trusted = input.trustedEnvelope === true ? trustedProviderFailureEnvelope(parsed) : void 0;
|
|
2987
|
+
const status3 = providerFailureStatus(input, text);
|
|
2988
|
+
const unstructuredText = input.body !== void 0 && (providerFailureRecord(parsed) !== void 0 || Array.isArray(parsed)) ? providerFailureProse(parsed) : text;
|
|
2989
|
+
const transientTransport = status3 === 408 || status3 === 425 || input.error instanceof Error && (input.error.name === "AbortError" || input.error.name === "TimeoutError") || status3 !== void 0 && status3 >= 500 || /stream ended before message_stop|stream ended without finish_reason|ended before completion/i.test(
|
|
2990
|
+
unstructuredText
|
|
2991
|
+
) || /^(?:(?:AbortError:\s*)?(?:This|The) operation was aborted|Request aborted)\.?$/i.test(unstructuredText.trim()) || /ECONNRESET|ETIMEDOUT|EPIPE|socket hang up|fetch failed|other side closed|network (?:error|failure)|(?:connection|stream) (?:reset|closed|terminated)|timed? ?out/i.test(
|
|
2992
|
+
unstructuredText
|
|
2993
|
+
) || /^terminated$/i.test(unstructuredText.trim()) || /\boverloaded\b/i.test(unstructuredText) || /<html[\s>][\s\S]{0,4000}\b(?:bad gateway|service unavailable|gateway timeout)\b/i.test(unstructuredText);
|
|
2994
|
+
let cause;
|
|
2995
|
+
if (trusted !== void 0) cause = trusted.cause;
|
|
2996
|
+
else if (status3 === 402) cause = "credit-or-quota-exhausted";
|
|
2997
|
+
else if (status3 === 429) cause = "rate-limited";
|
|
2998
|
+
else if (transientTransport) cause = "transient";
|
|
2999
|
+
else if (signalIncludes(signals, [
|
|
3000
|
+
"limit_source",
|
|
3001
|
+
"insufficient_quota",
|
|
3002
|
+
"quota_exceeded",
|
|
3003
|
+
"credit_limit",
|
|
3004
|
+
"billing_hard_limit",
|
|
3005
|
+
"payment_required"
|
|
3006
|
+
]) || providerFailureRecord(parsed)?.metadata !== void 0 && providerFailureRecord(providerFailureRecord(parsed)?.metadata)?.limit_source !== void 0)
|
|
3007
|
+
cause = "credit-or-quota-exhausted";
|
|
3008
|
+
else if (signalIncludes(signals, ["rate_limit", "too_many_requests"]) || /\brate[- ]limit(?:ed)?\b/i.test(unstructuredText))
|
|
3009
|
+
cause = "rate-limited";
|
|
3010
|
+
else if (signalIncludes(signals, ["provider_key_missing", "key_absent", "missing_api_key"])) cause = "key-absent";
|
|
3011
|
+
else if (status3 === 401 || signalIncludes(signals, ["authentication_error", "invalid_api_key", "invalid_key", "unauthorized"]))
|
|
3012
|
+
cause = "key-invalid";
|
|
3013
|
+
else if (signalIncludes(signals, ["model_not_found", "unknown_model", "model_unknown"])) cause = "model-unknown";
|
|
3014
|
+
else if (status3 === 400 || status3 === 422 || signalIncludes(signals, ["invalid_request_error", "invalid_json_schema", "bad_request", "unprocessable_entity"]))
|
|
3015
|
+
cause = "request-rejected";
|
|
3016
|
+
else cause = "permanent";
|
|
3017
|
+
const operatorUrl = /https?:\/\/[^\s"'<>]+/.exec(text)?.[0];
|
|
3018
|
+
return new ProviderFailure(cause, {
|
|
3019
|
+
...status3 !== void 0 ? { status: status3 } : {},
|
|
3020
|
+
...input.provider !== void 0 ? { provider: input.provider } : {},
|
|
3021
|
+
...input.model !== void 0 ? { model: input.model } : {},
|
|
3022
|
+
...operatorUrl !== void 0 ? { operatorUrl } : {},
|
|
3023
|
+
...trusted?.schemaRejection !== void 0 ? { schemaRejection: trusted.schemaRejection } : {}
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3026
|
+
function typedProviderFailureOf(error, seen = /* @__PURE__ */ new Set()) {
|
|
3027
|
+
if (error instanceof ProviderFailure) return error;
|
|
3028
|
+
const row2 = providerFailureRecord(error);
|
|
3029
|
+
if (!row2 || seen.has(row2)) return void 0;
|
|
3030
|
+
seen.add(row2);
|
|
3031
|
+
if (row2.name === "ProviderFailure" && isProviderFailureCause(row2.cause)) {
|
|
3032
|
+
return new ProviderFailure(row2.cause, {
|
|
3033
|
+
...typeof row2.status === "number" ? { status: row2.status } : {},
|
|
3034
|
+
...typeof row2.provider === "string" ? { provider: row2.provider } : {},
|
|
3035
|
+
...typeof row2.model === "string" ? { model: row2.model } : {},
|
|
3036
|
+
...typeof row2.operatorUrl === "string" ? { operatorUrl: row2.operatorUrl } : {},
|
|
3037
|
+
...typeof row2.keyVariable === "string" ? { keyVariable: row2.keyVariable } : {},
|
|
3038
|
+
...providerSchemaRejectionRecord(row2.schemaRejection) !== void 0 ? { schemaRejection: providerSchemaRejectionRecord(row2.schemaRejection) } : {}
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
return typedProviderFailureOf(row2.cause, seen);
|
|
3042
|
+
}
|
|
3043
|
+
function providerFailureOf(error) {
|
|
3044
|
+
return typedProviderFailureOf(error) ?? classifyProviderFailure({ error });
|
|
3045
|
+
}
|
|
3046
|
+
function providerFailureParks(cause) {
|
|
3047
|
+
return cause === "transient" || cause === "rate-limited" || cause === "credit-or-quota-exhausted";
|
|
3048
|
+
}
|
|
2824
3049
|
function wireOf(block) {
|
|
2825
3050
|
return block.wire ?? WIRE_ALIASES[block.type] ?? "openai-chat";
|
|
2826
3051
|
}
|
|
@@ -2859,10 +3084,41 @@ function parseModelRef(ref) {
|
|
|
2859
3084
|
}
|
|
2860
3085
|
return { provider: ref.slice(0, i), model: ref.slice(i + 1) };
|
|
2861
3086
|
}
|
|
2862
|
-
var WIRES, WIRE_ALIASES, INVOICE_APIS, BILLER_HARNESS_PROVIDERS, ANTHROPIC_API_KEY_ENV;
|
|
3087
|
+
var PROVIDER_FAILURE_CAUSES, ProviderFailure, providerFailureRecord, WIRES, WIRE_ALIASES, INVOICE_APIS, BILLER_HARNESS_PROVIDERS, ANTHROPIC_API_KEY_ENV;
|
|
2863
3088
|
var init_provider = __esm({
|
|
2864
3089
|
"../../src/core/provider.ts"() {
|
|
2865
3090
|
"use strict";
|
|
3091
|
+
PROVIDER_FAILURE_CAUSES = [
|
|
3092
|
+
"transient",
|
|
3093
|
+
"rate-limited",
|
|
3094
|
+
"credit-or-quota-exhausted",
|
|
3095
|
+
"key-absent",
|
|
3096
|
+
"key-invalid",
|
|
3097
|
+
"model-unknown",
|
|
3098
|
+
"request-rejected",
|
|
3099
|
+
"permanent"
|
|
3100
|
+
];
|
|
3101
|
+
ProviderFailure = class extends Error {
|
|
3102
|
+
name = "ProviderFailure";
|
|
3103
|
+
cause;
|
|
3104
|
+
status;
|
|
3105
|
+
provider;
|
|
3106
|
+
model;
|
|
3107
|
+
operatorUrl;
|
|
3108
|
+
keyVariable;
|
|
3109
|
+
schemaRejection;
|
|
3110
|
+
constructor(cause, details2 = {}) {
|
|
3111
|
+
super(providerFailureDiagnostic(cause, details2));
|
|
3112
|
+
this.cause = cause;
|
|
3113
|
+
this.status = details2.status;
|
|
3114
|
+
this.provider = details2.provider;
|
|
3115
|
+
this.model = details2.model;
|
|
3116
|
+
this.operatorUrl = details2.operatorUrl;
|
|
3117
|
+
this.keyVariable = details2.keyVariable;
|
|
3118
|
+
this.schemaRejection = details2.schemaRejection;
|
|
3119
|
+
}
|
|
3120
|
+
};
|
|
3121
|
+
providerFailureRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
2866
3122
|
WIRES = ["anthropic-messages", "openai-chat", "openai-responses"];
|
|
2867
3123
|
WIRE_ALIASES = {
|
|
2868
3124
|
anthropic: "anthropic-messages",
|
|
@@ -3285,7 +3541,7 @@ function whereCell(f, target) {
|
|
|
3285
3541
|
}
|
|
3286
3542
|
function verdictMarker(verdict, target) {
|
|
3287
3543
|
const head = target?.head ?? verdict?.head;
|
|
3288
|
-
const
|
|
3544
|
+
const payload2 = {
|
|
3289
3545
|
verdict: verdict?.verdict ?? "none",
|
|
3290
3546
|
...head ? { head } : {},
|
|
3291
3547
|
...verdict?.findings ? {
|
|
@@ -3299,7 +3555,7 @@ function verdictMarker(verdict, target) {
|
|
|
3299
3555
|
}))
|
|
3300
3556
|
} : {}
|
|
3301
3557
|
};
|
|
3302
|
-
return `<!-- switchboard:verdict ${JSON.stringify(
|
|
3558
|
+
return `<!-- switchboard:verdict ${JSON.stringify(payload2).replace(/-->/g, "--\\u003e")} -->`;
|
|
3303
3559
|
}
|
|
3304
3560
|
function buildReviewPostBody(answer, verdict, target) {
|
|
3305
3561
|
const facts2 = [
|
|
@@ -4756,11 +5012,11 @@ function analyzeRunFriction(events, opts = {}) {
|
|
|
4756
5012
|
if (promised) {
|
|
4757
5013
|
const line4 = answer.text.slice(0, promised.index).split("\n").pop() + answer.text.slice(promised.index).split("\n")[0];
|
|
4758
5014
|
const trimmed2 = line4.trim();
|
|
4759
|
-
const
|
|
5015
|
+
const quoted2 = trimmed2.length > 120 ? `\u2026${trimmed2.slice(trimmed2.length - 119)}` : trimmed2;
|
|
4760
5016
|
findings.push({
|
|
4761
5017
|
category: "unkept_promise",
|
|
4762
5018
|
severity: "low",
|
|
4763
|
-
summary: `unkept promise: the reply says a file is attached but the run produced none \u2014 "${
|
|
5019
|
+
summary: `unkept promise: the reply says a file is attached but the run produced none \u2014 "${quoted2}"`,
|
|
4764
5020
|
eventIndex: answer.index
|
|
4765
5021
|
});
|
|
4766
5022
|
}
|
|
@@ -5507,6 +5763,7 @@ function isCoordinatorUnit(v) {
|
|
|
5507
5763
|
if (r.issue !== void 0 && !isFinite(r.issue)) return false;
|
|
5508
5764
|
if (r.pr !== void 0 && !isPr(r.pr)) return false;
|
|
5509
5765
|
if (r.resume !== void 0 && !isResume(r.resume)) return false;
|
|
5766
|
+
if (r.record !== void 0 && (typeof r.record !== "string" || !/^\d{4}$/.test(r.record))) return false;
|
|
5510
5767
|
if (r.lastPush !== void 0 && !isText(r.lastPush)) return false;
|
|
5511
5768
|
if (r.segments !== void 0 && (!Array.isArray(r.segments) || !r.segments.every(isSegment))) return false;
|
|
5512
5769
|
if (r.idle !== void 0 && !isUnitIdle(r.idle)) return false;
|
|
@@ -5536,22 +5793,22 @@ async function sendUnitNudge(workflow, key) {
|
|
|
5536
5793
|
async function sendChecksSettled(workflow, instance, headSha, settledAt) {
|
|
5537
5794
|
if (!workflow) return { kind: "no-binding", instance };
|
|
5538
5795
|
const type = checksSettledEventType(headSha);
|
|
5539
|
-
const
|
|
5796
|
+
const payload2 = { headSha, settledAt };
|
|
5540
5797
|
try {
|
|
5541
5798
|
const handle2 = await workflow.get(instance);
|
|
5542
|
-
await handle2.sendEvent({ type, payload });
|
|
5799
|
+
await handle2.sendEvent({ type, payload: payload2 });
|
|
5543
5800
|
return { kind: "sent", instance, type };
|
|
5544
5801
|
} catch (err2) {
|
|
5545
5802
|
return { kind: "failed", instance, type, reason: err2 instanceof Error ? err2.message : String(err2) };
|
|
5546
5803
|
}
|
|
5547
5804
|
}
|
|
5548
|
-
async function sendPullMerged(workflow, key,
|
|
5805
|
+
async function sendPullMerged(workflow, key, payload2) {
|
|
5549
5806
|
const instance = key.instanceId;
|
|
5550
5807
|
if (!workflow) return { kind: "no-binding", instance };
|
|
5551
5808
|
const type = pullMergedEventType(key);
|
|
5552
5809
|
try {
|
|
5553
5810
|
const handle2 = await workflow.get(instance);
|
|
5554
|
-
await handle2.sendEvent({ type, payload });
|
|
5811
|
+
await handle2.sendEvent({ type, payload: payload2 });
|
|
5555
5812
|
return { kind: "sent", instance, type };
|
|
5556
5813
|
} catch (err2) {
|
|
5557
5814
|
return { kind: "failed", instance, type, reason: err2 instanceof Error ? err2.message : String(err2) };
|
|
@@ -5785,6 +6042,7 @@ var init_pipelineStanding = __esm({
|
|
|
5785
6042
|
};
|
|
5786
6043
|
ENDING_STAGE = {
|
|
5787
6044
|
merged: "merged",
|
|
6045
|
+
closed: "ended",
|
|
5788
6046
|
already_landed: "merged",
|
|
5789
6047
|
merge_ready: "merge-ready",
|
|
5790
6048
|
held: "ended",
|
|
@@ -5806,6 +6064,7 @@ var init_pipelineStanding = __esm({
|
|
|
5806
6064
|
};
|
|
5807
6065
|
ENDING_WORDS = {
|
|
5808
6066
|
merged: "merged",
|
|
6067
|
+
closed: "closed",
|
|
5809
6068
|
already_landed: "merged",
|
|
5810
6069
|
merge_ready: "merge-ready",
|
|
5811
6070
|
held: "held",
|
|
@@ -5865,6 +6124,16 @@ function instanceIdOfEvents(events) {
|
|
|
5865
6124
|
for (const e of events) if (e.type === "ship_handoff") id = e.instanceId;
|
|
5866
6125
|
return id;
|
|
5867
6126
|
}
|
|
6127
|
+
function decisionRecordOfEvents(events) {
|
|
6128
|
+
let reservation;
|
|
6129
|
+
for (const event of events)
|
|
6130
|
+
if (event.type === "run_meta" && event.record !== void 0)
|
|
6131
|
+
reservation = {
|
|
6132
|
+
record: event.record,
|
|
6133
|
+
...event.recordTaskKey !== void 0 ? { recordTaskKey: event.recordTaskKey } : {}
|
|
6134
|
+
};
|
|
6135
|
+
return reservation;
|
|
6136
|
+
}
|
|
5868
6137
|
function prOfEvents(events) {
|
|
5869
6138
|
let pr;
|
|
5870
6139
|
for (const e of events) {
|
|
@@ -5939,6 +6208,7 @@ function operatorOfEvents(events) {
|
|
|
5939
6208
|
...e.request !== void 0 ? { request: e.request } : {},
|
|
5940
6209
|
...e.refusalCause !== void 0 ? { refusalCause: e.refusalCause } : {},
|
|
5941
6210
|
...e.refusalText !== void 0 ? { refusalText: e.refusalText } : {},
|
|
6211
|
+
...e.providerFailure !== void 0 ? { providerFailure: e.providerFailure } : {},
|
|
5942
6212
|
...e.attempts ? {
|
|
5943
6213
|
attempts: e.attempts.map((a) => ({
|
|
5944
6214
|
outcome: a.outcome,
|
|
@@ -6150,6 +6420,10 @@ function isRunRecord(v) {
|
|
|
6150
6420
|
if (!isOptionalString(r.label) || !isOptionalString(r.agent) || !isOptionalString(r.model) || !isOptionalString(r.repo))
|
|
6151
6421
|
return false;
|
|
6152
6422
|
if (!isOptionalString(r.activity) || !isOptionalString(r.sourceUrl) || !isOptionalString(r.userName)) return false;
|
|
6423
|
+
if (r.record !== void 0 && (typeof r.record !== "string" || !/^\d{4}$/.test(r.record))) return false;
|
|
6424
|
+
if (r.recordTaskKey !== void 0 && (typeof r.recordTaskKey !== "string" || !/^[0-9a-f]{16}$/.test(r.recordTaskKey)))
|
|
6425
|
+
return false;
|
|
6426
|
+
if (r.headSha !== void 0 && (typeof r.headSha !== "string" || !REVIEW_HEAD_PATTERN.test(r.headSha))) return false;
|
|
6153
6427
|
if (r.handoff !== void 0 && !isHandoffShape(r.handoff)) return false;
|
|
6154
6428
|
if (r.verdict !== void 0 && !isReviewVerdictShape(r.verdict)) return false;
|
|
6155
6429
|
if (r.reviewHead !== void 0 && (typeof r.reviewHead !== "string" || !REVIEW_HEAD_PATTERN.test(r.reviewHead)))
|
|
@@ -8335,13 +8609,13 @@ var init_config2 = __esm({
|
|
|
8335
8609
|
describe() {
|
|
8336
8610
|
return `state Worker ${this.baseUrl} (ConfigDO)`;
|
|
8337
8611
|
}
|
|
8338
|
-
async post(path,
|
|
8612
|
+
async post(path, payload2) {
|
|
8339
8613
|
let res;
|
|
8340
8614
|
try {
|
|
8341
8615
|
res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
8342
8616
|
method: "POST",
|
|
8343
8617
|
headers: { authorization: `Bearer ${this.opts.token}`, "content-type": "application/json" },
|
|
8344
|
-
body: JSON.stringify(
|
|
8618
|
+
body: JSON.stringify(payload2),
|
|
8345
8619
|
signal: AbortSignal.timeout(CONFIG_WORKER_TIMEOUT_MS)
|
|
8346
8620
|
});
|
|
8347
8621
|
} catch (err2) {
|
|
@@ -10456,11 +10730,11 @@ function resolveImportCandidates(fromFile, specifier) {
|
|
|
10456
10730
|
const dir = fromFile.includes("/") ? fromFile.slice(0, fromFile.lastIndexOf("/")) : "";
|
|
10457
10731
|
const joined = normalizePath(`${dir}/${specifier}`);
|
|
10458
10732
|
const ext = /\.[a-z]+$/i.exec(joined)?.[0] ?? "";
|
|
10459
|
-
const
|
|
10460
|
-
if (JS_TO_TS[ext])
|
|
10461
|
-
if (!ext)
|
|
10462
|
-
|
|
10463
|
-
return
|
|
10733
|
+
const candidates2 = [];
|
|
10734
|
+
if (JS_TO_TS[ext]) candidates2.push(joined.slice(0, -ext.length) + JS_TO_TS[ext]);
|
|
10735
|
+
if (!ext) candidates2.push(`${joined}.ts`);
|
|
10736
|
+
candidates2.push(joined, `${joined}/index.ts`);
|
|
10737
|
+
return candidates2;
|
|
10464
10738
|
}
|
|
10465
10739
|
async function importClosure(entry, read) {
|
|
10466
10740
|
const entrySource = await read(entry);
|
|
@@ -11556,8 +11830,8 @@ var init_runStoreWorker = __esm({
|
|
|
11556
11830
|
}
|
|
11557
11831
|
/** POST a JSON body and classify the outcome. The body is a STRING; the
|
|
11558
11832
|
* runtime sets its numeric Content-Length (never hand-set — see header). */
|
|
11559
|
-
async post(path,
|
|
11560
|
-
const body = JSON.stringify(
|
|
11833
|
+
async post(path, payload2, span) {
|
|
11834
|
+
const body = JSON.stringify(payload2);
|
|
11561
11835
|
let res;
|
|
11562
11836
|
try {
|
|
11563
11837
|
res = await tracedFetch(
|
|
@@ -11841,8 +12115,8 @@ function rolloutTargetFromDeployOutput(output) {
|
|
|
11841
12115
|
const at = text.indexOf("Container application changes");
|
|
11842
12116
|
if (at < 0) return null;
|
|
11843
12117
|
const lines = text.slice(at).split("\n").map((l) => l.replace(SECTION_GUTTER, "").trimEnd());
|
|
11844
|
-
const imageOn = (
|
|
11845
|
-
for (const l of
|
|
12118
|
+
const imageOn = (candidates2) => {
|
|
12119
|
+
for (const l of candidates2) {
|
|
11846
12120
|
const m = /^\+?\s*"image":\s*"([^"]+)"/.exec(l);
|
|
11847
12121
|
if (m) return m[1];
|
|
11848
12122
|
}
|
|
@@ -12043,7 +12317,7 @@ async function loadProfileOnHost(env = process.env, sourceIO = hostConfigSourceI
|
|
|
12043
12317
|
return profileFromJson(read.text, override, "profile");
|
|
12044
12318
|
}
|
|
12045
12319
|
}
|
|
12046
|
-
const
|
|
12320
|
+
const candidates2 = override ? [
|
|
12047
12321
|
{
|
|
12048
12322
|
path: override,
|
|
12049
12323
|
origin: "profile",
|
|
@@ -12053,7 +12327,7 @@ async function loadProfileOnHost(env = process.env, sourceIO = hostConfigSourceI
|
|
|
12053
12327
|
{ path: PROFILE_PATH, origin: "profile", abs: installationPath(OPERATOR_ROOT, PROFILE_PATH) },
|
|
12054
12328
|
{ path: PROFILE_EXAMPLE_PATH, origin: "example", abs: assetPath(OPERATOR_ROOT, PROFILE_EXAMPLE_PATH) }
|
|
12055
12329
|
];
|
|
12056
|
-
for (const c of
|
|
12330
|
+
for (const c of candidates2) {
|
|
12057
12331
|
const abs = c.abs;
|
|
12058
12332
|
if (!existsSync6(abs)) {
|
|
12059
12333
|
if (c.origin === "profile" && override) throw new Error(`${PROFILE_ENV}=${override}: no such file`);
|
|
@@ -15182,6 +15456,7 @@ var init_refusal = __esm({
|
|
|
15182
15456
|
plan_runner_state_unread: "system",
|
|
15183
15457
|
plan_units_merged: "request",
|
|
15184
15458
|
plan_history_unavailable: "system",
|
|
15459
|
+
decision_record_store_unavailable: "system",
|
|
15185
15460
|
plan_runner_conflict: "system",
|
|
15186
15461
|
plan_instance_orphaned: "system",
|
|
15187
15462
|
plan_start_failed: "system",
|
|
@@ -15998,10 +16273,11 @@ var init_resident = __esm({
|
|
|
15998
16273
|
}
|
|
15999
16274
|
/** Bind/reuse this thread's worktree. Legible errors for every named
|
|
16000
16275
|
* refusal the service can answer with. Answers the binding the resident
|
|
16001
|
-
* reported: the bound ref —
|
|
16002
|
-
*
|
|
16003
|
-
*
|
|
16004
|
-
* `rebound` / `rebindRefused`
|
|
16276
|
+
* reported: the bound ref — a named `refHint` must be that ref, while the
|
|
16277
|
+
* sticky binding may answer a different ref only when the caller named none
|
|
16278
|
+
* (`refByDefault` or an `ownPr`-derived hint). The Worker also persists a named ref as the new sticky
|
|
16279
|
+
* binding (item 16). `rebound` / `rebindRefused` report the legacy own-PR
|
|
16280
|
+
* movement, and the sha says which commit the worktree is at. A
|
|
16005
16281
|
* 200 without both fields is a malformed resident (the attach contract
|
|
16006
16282
|
* always carries them) and is an error, never a half-bound executor. A
|
|
16007
16283
|
* refusal the Worker typed as the platform's transient (`isTransientRefusal`:
|
|
@@ -16142,10 +16418,15 @@ var init_resident = __esm({
|
|
|
16142
16418
|
if (typeof data.ref !== "string" || typeof data.sha !== "string") {
|
|
16143
16419
|
throw new Error(`resident attach: malformed answer for ${this.opts.resource} (missing ref/sha)`);
|
|
16144
16420
|
}
|
|
16421
|
+
const returned = returnedOf(data.returned);
|
|
16422
|
+
if (this.opts.refHint !== void 0 && !this.opts.refByDefault && this.opts.ownPr === void 0 && data.ref !== this.opts.refHint) {
|
|
16423
|
+
throw new Error(
|
|
16424
|
+
`resident attach: named ref mismatch for ${this.opts.resource} (asked for ${JSON.stringify(this.opts.refHint)}, got ${JSON.stringify(data.ref)})`
|
|
16425
|
+
);
|
|
16426
|
+
}
|
|
16145
16427
|
const trace = sanitizeGraftedSteps(data.trace);
|
|
16146
16428
|
const rebound = reboundOf(data.rebound);
|
|
16147
16429
|
const rebindRefused = rebindRefusedOf(data.rebindRefused);
|
|
16148
|
-
const returned = returnedOf(data.returned);
|
|
16149
16430
|
this.lastBinding = {
|
|
16150
16431
|
ref: data.ref,
|
|
16151
16432
|
sha: data.sha,
|
|
@@ -16616,11 +16897,11 @@ function matchOf(typed, candidate) {
|
|
|
16616
16897
|
const edits = editDistance(typed, candidate);
|
|
16617
16898
|
return edits <= editBudget(typed) ? { kind: "edit", edits } : void 0;
|
|
16618
16899
|
}
|
|
16619
|
-
function nearMatch(typed,
|
|
16900
|
+
function nearMatch(typed, candidates2) {
|
|
16620
16901
|
const needle = typed.toLowerCase();
|
|
16621
|
-
if (
|
|
16902
|
+
if (candidates2.some((c) => c.toLowerCase() === needle)) return {};
|
|
16622
16903
|
const within = [];
|
|
16623
|
-
for (const candidate of
|
|
16904
|
+
for (const candidate of candidates2) {
|
|
16624
16905
|
const match = matchOf(needle, candidate.toLowerCase());
|
|
16625
16906
|
if (match)
|
|
16626
16907
|
within.push(match.kind === "edit" ? { candidate, edits: match.edits } : { candidate, extended: match.extended });
|
|
@@ -16747,12 +17028,12 @@ async function mintCore(scope, span) {
|
|
|
16747
17028
|
function appJwt(credentials) {
|
|
16748
17029
|
const now = Math.floor(systemClock() / 1e3);
|
|
16749
17030
|
const header4 = b64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
16750
|
-
const
|
|
17031
|
+
const payload2 = b64url(JSON.stringify({ iat: now - 60, exp: now + 540, iss: credentials.appId.reveal() }));
|
|
16751
17032
|
const signer = createSign("RSA-SHA256");
|
|
16752
|
-
signer.update(`${header4}.${
|
|
17033
|
+
signer.update(`${header4}.${payload2}`);
|
|
16753
17034
|
const pem = credentials.privateKey.reveal().replace(/\\n/g, "\n");
|
|
16754
|
-
const
|
|
16755
|
-
return `${header4}.${
|
|
17035
|
+
const signature2 = signer.sign(pem).toString("base64url");
|
|
17036
|
+
return `${header4}.${payload2}.${signature2}`;
|
|
16756
17037
|
}
|
|
16757
17038
|
function b64url(s) {
|
|
16758
17039
|
return Buffer.from(s).toString("base64url");
|
|
@@ -16987,11 +17268,11 @@ async function createBranchRef(repo, branch2, fromRef) {
|
|
|
16987
17268
|
if (res.status === 422 && /already exists/i.test(text)) return;
|
|
16988
17269
|
throw new Error(`branch create failed for ${branch2}: HTTP ${res.status} ${redactAndCap(text, 300)}`);
|
|
16989
17270
|
}
|
|
16990
|
-
function resolveBaseRef(
|
|
16991
|
-
return
|
|
17271
|
+
function resolveBaseRef(candidates2, defaultBranch) {
|
|
17272
|
+
return candidates2.find((c) => c !== void 0) ?? defaultBranch;
|
|
16992
17273
|
}
|
|
16993
|
-
async function resolveBaseRefLazy(
|
|
16994
|
-
const explicit =
|
|
17274
|
+
async function resolveBaseRefLazy(candidates2, repo, fetchInfo) {
|
|
17275
|
+
const explicit = candidates2.find((c) => c !== void 0);
|
|
16995
17276
|
if (explicit) return explicit;
|
|
16996
17277
|
const info = await fetchInfo(repo).catch(() => void 0);
|
|
16997
17278
|
return info?.defaultBranch;
|
|
@@ -17113,7 +17394,22 @@ async function fetchPullRequestFacts(pr) {
|
|
|
17113
17394
|
const prSha = typeof data.head?.sha === "string" && /^[0-9a-f]{40}$/.test(data.head.sha) ? data.head.sha : void 0;
|
|
17114
17395
|
const sameRepoHead = headRepo === pr.repo.toLowerCase();
|
|
17115
17396
|
const headRef = typeof data.head?.ref === "string" && data.head.ref ? data.head.ref : void 0;
|
|
17116
|
-
const
|
|
17397
|
+
const headBranchExists = sameRepoHead && headRef !== void 0 ? await fetchRefExists(pr.repo, headRef) : void 0;
|
|
17398
|
+
const sha = sameRepoHead && headRef !== void 0 && headBranchExists !== false ? preferRefTip(`${pr.repo}#${pr.number}`, prSha, await headRefTipSha(pr.repo, headRef, headers), headRef) : prSha;
|
|
17399
|
+
let closedBy = typeof data.closed_by?.login === "string" ? data.closed_by.login : void 0;
|
|
17400
|
+
if (data.state === "closed" && !(typeof data.merged_at === "string" && data.merged_at) && closedBy === void 0) {
|
|
17401
|
+
try {
|
|
17402
|
+
const issue = await fetch(`https://api.github.com/repos/${pr.repo}/issues/${pr.number}`, {
|
|
17403
|
+
headers,
|
|
17404
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
17405
|
+
});
|
|
17406
|
+
if (issue.ok) {
|
|
17407
|
+
const row2 = await issue.json().catch(() => null);
|
|
17408
|
+
if (typeof row2?.closed_by?.login === "string") closedBy = row2.closed_by.login;
|
|
17409
|
+
}
|
|
17410
|
+
} catch {
|
|
17411
|
+
}
|
|
17412
|
+
}
|
|
17117
17413
|
return {
|
|
17118
17414
|
state: data.state,
|
|
17119
17415
|
...data.user && (typeof data.user.login === "string" || typeof data.user.id === "number") ? {
|
|
@@ -17124,6 +17420,7 @@ async function fetchPullRequestFacts(pr) {
|
|
|
17124
17420
|
} : {},
|
|
17125
17421
|
...headRef !== void 0 ? { headRef } : {},
|
|
17126
17422
|
...sha ? { headSha: sha } : {},
|
|
17423
|
+
...headBranchExists !== void 0 ? { headBranchExists } : {},
|
|
17127
17424
|
sameRepoHead,
|
|
17128
17425
|
...typeof data.base?.ref === "string" && data.base.ref ? { baseRef: data.base.ref } : {},
|
|
17129
17426
|
...typeof data.html_url === "string" ? { htmlUrl: data.html_url } : {},
|
|
@@ -17136,8 +17433,10 @@ async function fetchPullRequestFacts(pr) {
|
|
|
17136
17433
|
// reports a test-merge sha under `merge_commit_sha`.
|
|
17137
17434
|
...typeof data.merged_at === "string" && data.merged_at ? {
|
|
17138
17435
|
mergedAt: data.merged_at,
|
|
17139
|
-
...typeof data.merge_commit_sha === "string" && /^[0-9a-f]{40}$/.test(data.merge_commit_sha) ? { mergeCommitSha: data.merge_commit_sha } : {}
|
|
17140
|
-
|
|
17436
|
+
...typeof data.merge_commit_sha === "string" && /^[0-9a-f]{40}$/.test(data.merge_commit_sha) ? { mergeCommitSha: data.merge_commit_sha } : {},
|
|
17437
|
+
...typeof data.merged_by?.login === "string" ? { mergedBy: data.merged_by.login } : {}
|
|
17438
|
+
} : {},
|
|
17439
|
+
...closedBy !== void 0 ? { closedBy } : {}
|
|
17141
17440
|
};
|
|
17142
17441
|
}
|
|
17143
17442
|
async function mergePullRequest(pr, opts) {
|
|
@@ -17439,6 +17738,56 @@ async function rerunFailedJobs(repo, sha, names) {
|
|
|
17439
17738
|
}
|
|
17440
17739
|
return true;
|
|
17441
17740
|
}
|
|
17741
|
+
async function fetchDecisionRecordClaims(repo) {
|
|
17742
|
+
const token2 = await requireToken();
|
|
17743
|
+
const get = async (url, what) => {
|
|
17744
|
+
const res = await fetch(url, { headers: apiHeaders(token2), signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
|
|
17745
|
+
if (!res.ok) {
|
|
17746
|
+
const text = await res.text().catch(() => "");
|
|
17747
|
+
throw new Error(`${what} could not be read: HTTP ${res.status} ${redactAndCap(text, 300)}`);
|
|
17748
|
+
}
|
|
17749
|
+
return res.json().catch(() => null);
|
|
17750
|
+
};
|
|
17751
|
+
const numbers = /* @__PURE__ */ new Set();
|
|
17752
|
+
const claim = (path) => {
|
|
17753
|
+
if (typeof path !== "string") return;
|
|
17754
|
+
const number = /^docs\/decisions\/(\d{4})-[^/]+\.md$/.exec(path)?.[1];
|
|
17755
|
+
if (number !== void 0) numbers.add(number);
|
|
17756
|
+
};
|
|
17757
|
+
const main2 = await get(
|
|
17758
|
+
`https://api.github.com/repos/${repo}/contents/docs/decisions?ref=main&per_page=1000`,
|
|
17759
|
+
`origin/main's decision records in ${repo}`
|
|
17760
|
+
);
|
|
17761
|
+
if (!Array.isArray(main2))
|
|
17762
|
+
throw new Error(`origin/main's decision records in ${repo} could not be read: malformed answer`);
|
|
17763
|
+
for (const row2 of main2) claim(row2.path);
|
|
17764
|
+
const pulls = [];
|
|
17765
|
+
for (let page2 = 1; ; page2 += 1) {
|
|
17766
|
+
const rows = await get(
|
|
17767
|
+
`https://api.github.com/repos/${repo}/pulls?state=open&per_page=100&page=${page2}`,
|
|
17768
|
+
`the open pull requests of ${repo}`
|
|
17769
|
+
);
|
|
17770
|
+
if (!Array.isArray(rows)) throw new Error(`the open pull requests of ${repo} could not be read: malformed answer`);
|
|
17771
|
+
for (const row2 of rows)
|
|
17772
|
+
if (typeof row2.number === "number" && Number.isInteger(row2.number) && row2.number > 0) pulls.push(row2.number);
|
|
17773
|
+
if (rows.length < 100) break;
|
|
17774
|
+
}
|
|
17775
|
+
await Promise.all(
|
|
17776
|
+
pulls.map(async (number) => {
|
|
17777
|
+
for (let page2 = 1; ; page2 += 1) {
|
|
17778
|
+
const rows = await get(
|
|
17779
|
+
`https://api.github.com/repos/${repo}/pulls/${number}/files?per_page=100&page=${page2}`,
|
|
17780
|
+
`the changed files of ${repo}#${number}`
|
|
17781
|
+
);
|
|
17782
|
+
if (!Array.isArray(rows))
|
|
17783
|
+
throw new Error(`the changed files of ${repo}#${number} could not be read: malformed answer`);
|
|
17784
|
+
for (const row2 of rows) claim(row2.filename);
|
|
17785
|
+
if (rows.length < 100) break;
|
|
17786
|
+
}
|
|
17787
|
+
})
|
|
17788
|
+
);
|
|
17789
|
+
return numbers;
|
|
17790
|
+
}
|
|
17442
17791
|
async function listOpenPullRequests(repo) {
|
|
17443
17792
|
const token2 = await requireToken();
|
|
17444
17793
|
const res = await fetch(`https://api.github.com/repos/${repo}/pulls?state=open&per_page=100`, {
|
|
@@ -18368,9 +18717,9 @@ function residentSlugsLister(cfg, secrets = processSecrets) {
|
|
|
18368
18717
|
}
|
|
18369
18718
|
async function nearOnboarded(cfg, typed) {
|
|
18370
18719
|
const list = residentSlugsLister(cfg);
|
|
18371
|
-
const
|
|
18372
|
-
if (!
|
|
18373
|
-
return nearMatch(typed,
|
|
18720
|
+
const candidates2 = await list?.().catch(() => void 0);
|
|
18721
|
+
if (!candidates2 || candidates2.length === 0) return void 0;
|
|
18722
|
+
return nearMatch(typed, candidates2).guess;
|
|
18374
18723
|
}
|
|
18375
18724
|
async function probeResident(cfg, token2, resource, span, stop) {
|
|
18376
18725
|
if (probeOutage && systemClock() < probeOutage.until) {
|
|
@@ -20474,10 +20823,10 @@ var init_costs = __esm({
|
|
|
20474
20823
|
|
|
20475
20824
|
// ../../src/core/costsBy.ts
|
|
20476
20825
|
function coverageFrom(range, usage, generatedAt) {
|
|
20477
|
-
const
|
|
20478
|
-
if (usage.earliestFinishedAt !== void 0)
|
|
20479
|
-
if (usage.retentionDays > 0)
|
|
20480
|
-
const from =
|
|
20826
|
+
const candidates2 = [range.from];
|
|
20827
|
+
if (usage.earliestFinishedAt !== void 0) candidates2.push(dayOfMs(usage.earliestFinishedAt));
|
|
20828
|
+
if (usage.retentionDays > 0) candidates2.push(dayOfMs(generatedAt - usage.retentionDays * DAY_MS));
|
|
20829
|
+
const from = candidates2.reduce((m, d) => d > m ? d : m);
|
|
20481
20830
|
return from > range.to ? range.to : from;
|
|
20482
20831
|
}
|
|
20483
20832
|
function slicesOf(cells, dimension) {
|
|
@@ -24728,10 +25077,10 @@ function clusterFriction(records, opts = {}) {
|
|
|
24728
25077
|
const minRuns = opts.minRuns ?? DEFAULT_MIN_RUNS;
|
|
24729
25078
|
const ordered = [...records].sort((a, b) => a.finishedAt - b.finishedAt || a.runId.localeCompare(b.runId));
|
|
24730
25079
|
const acc = /* @__PURE__ */ new Map();
|
|
24731
|
-
const add = (key, kind,
|
|
25080
|
+
const add = (key, kind, signature2, rec2, example, durationMs) => {
|
|
24732
25081
|
let a = acc.get(key);
|
|
24733
25082
|
if (!a) {
|
|
24734
|
-
a = { kind, signature, runIds: /* @__PURE__ */ new Set(), occurrences: 0, durationMs: 0, severity: "low", examples: [] };
|
|
25083
|
+
a = { kind, signature: signature2, runIds: /* @__PURE__ */ new Set(), occurrences: 0, durationMs: 0, severity: "low", examples: [] };
|
|
24735
25084
|
acc.set(key, a);
|
|
24736
25085
|
}
|
|
24737
25086
|
a.runIds.add(rec2.runId);
|
|
@@ -25057,10 +25406,10 @@ function parseRunEventLines(text) {
|
|
|
25057
25406
|
for (const raw of text.split("\n")) {
|
|
25058
25407
|
const line4 = raw.trim();
|
|
25059
25408
|
if (line4 === "" || line4.startsWith(":") || /^(retry|event|id):/.test(line4)) continue;
|
|
25060
|
-
const
|
|
25409
|
+
const payload2 = line4.startsWith("data:") ? line4.slice("data:".length).trim() : line4;
|
|
25061
25410
|
let parsed;
|
|
25062
25411
|
try {
|
|
25063
|
-
parsed = JSON.parse(
|
|
25412
|
+
parsed = JSON.parse(payload2);
|
|
25064
25413
|
} catch {
|
|
25065
25414
|
skipped++;
|
|
25066
25415
|
continue;
|
|
@@ -26295,9 +26644,9 @@ function wellKnownCandidates(base, suffix) {
|
|
|
26295
26644
|
async function discover(fetchImpl, serverUrl2, hintedMetadataUrl) {
|
|
26296
26645
|
const server = assertUrlAllowed(serverUrl2);
|
|
26297
26646
|
const resource = `${server.origin}${server.pathname.replace(/\/+$/, "")}`;
|
|
26298
|
-
const
|
|
26647
|
+
const candidates2 = [...hintedMetadataUrl ? [hintedMetadataUrl] : [], ...wellKnownCandidates(server, PRM_SUFFIX)];
|
|
26299
26648
|
let prm;
|
|
26300
|
-
for (const url of
|
|
26649
|
+
for (const url of candidates2) {
|
|
26301
26650
|
prm = await getJson(fetchImpl, url, "resource metadata");
|
|
26302
26651
|
if (prm) break;
|
|
26303
26652
|
}
|
|
@@ -28813,24 +29162,24 @@ function parseReflection(raw, prov, knownIds) {
|
|
|
28813
29162
|
const parsed = REFLECTION_ENVELOPE.parse(raw);
|
|
28814
29163
|
if (!parsed.ok) return { ok: false, error: parsed.failure.observed };
|
|
28815
29164
|
const obj2 = parsed.value;
|
|
28816
|
-
const
|
|
29165
|
+
const candidates2 = [];
|
|
28817
29166
|
let rejected = 0;
|
|
28818
29167
|
for (const f of obj2.facts) {
|
|
28819
|
-
if (
|
|
29168
|
+
if (candidates2.length >= MAX_REFLECTION_FACTS) break;
|
|
28820
29169
|
const fact = parseFact(f, prov, knownIds);
|
|
28821
29170
|
if (!fact) continue;
|
|
28822
29171
|
if (rejectionMarkers(fact.text).length > 0) {
|
|
28823
29172
|
rejected += 1;
|
|
28824
29173
|
continue;
|
|
28825
29174
|
}
|
|
28826
|
-
|
|
29175
|
+
candidates2.push(fact);
|
|
28827
29176
|
}
|
|
28828
29177
|
const summary = cleanText(obj2.summary);
|
|
28829
29178
|
if (summary) {
|
|
28830
|
-
const audience = SUMMARY_INHERITANCE.find((a) =>
|
|
28831
|
-
|
|
29179
|
+
const audience = SUMMARY_INHERITANCE.find((a) => candidates2.some((c) => c.audience === a)) ?? "org";
|
|
29180
|
+
candidates2.push({ kind: "summary", text: summary, audience, ...prov });
|
|
28832
29181
|
}
|
|
28833
|
-
return { ok: true, candidates, offered: obj2.facts.length, rejected };
|
|
29182
|
+
return { ok: true, candidates: candidates2, offered: obj2.facts.length, rejected };
|
|
28834
29183
|
}
|
|
28835
29184
|
function parseFact(raw, prov, knownIds) {
|
|
28836
29185
|
if (typeof raw !== "object" || raw === null) return void 0;
|
|
@@ -28939,14 +29288,21 @@ async function reflect(deps) {
|
|
|
28939
29288
|
const seen = /* @__PURE__ */ new Set();
|
|
28940
29289
|
const existing = [...await windowP, ...hits].filter((r) => !seen.has(r.id) && (seen.add(r.id), true));
|
|
28941
29290
|
const text = buildReflectionInput({ history: deps.history, request: deps.request, answer: deps.answer, existing });
|
|
28942
|
-
|
|
28943
|
-
|
|
28944
|
-
|
|
28945
|
-
|
|
28946
|
-
|
|
28947
|
-
|
|
28948
|
-
|
|
28949
|
-
|
|
29291
|
+
let result;
|
|
29292
|
+
try {
|
|
29293
|
+
result = await deps.provider.complete({
|
|
29294
|
+
model: deps.model,
|
|
29295
|
+
system: REFLECTION_SYSTEM,
|
|
29296
|
+
messages: [{ role: "user", content: [{ type: "text", text }] }],
|
|
29297
|
+
maxTokens: REFLECTION_MAX_TOKENS,
|
|
29298
|
+
...deps.effort !== void 0 ? { effort: deps.effort } : {},
|
|
29299
|
+
...deps.effortWord !== void 0 ? { effortWord: deps.effortWord } : {}
|
|
29300
|
+
});
|
|
29301
|
+
} catch (err2) {
|
|
29302
|
+
const failure2 = providerFailureOf(err2);
|
|
29303
|
+
warn(`reflection skipped: ${renderProviderFailure(failure2.cause)}`);
|
|
29304
|
+
return;
|
|
29305
|
+
}
|
|
28950
29306
|
const reply = result.content.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
28951
29307
|
const prov = { sourceThreadKey: deps.sourceThreadKey, sourceRunId: deps.sourceRunId };
|
|
28952
29308
|
const parsed = parseReflection(reply, prov, new Set(existing.map((r) => r.id)));
|
|
@@ -29020,6 +29376,7 @@ var REFLECT_MIN_TURNS, MAX_REFLECTION_FACTS, MIN_REFLECTION_CONFIDENCE, MAX_KEYW
|
|
|
29020
29376
|
var init_reflection = __esm({
|
|
29021
29377
|
"../../src/core/memory/reflection.ts"() {
|
|
29022
29378
|
"use strict";
|
|
29379
|
+
init_provider();
|
|
29023
29380
|
init_authz();
|
|
29024
29381
|
init_runEvents();
|
|
29025
29382
|
init_llmOutput();
|
|
@@ -31344,6 +31701,7 @@ function assembleRunRecord(input) {
|
|
|
31344
31701
|
const route2 = input.route ?? routeOfEvents(events);
|
|
31345
31702
|
const operator = operatorOfEvents(events);
|
|
31346
31703
|
const instanceId = instanceIdOfEvents(events);
|
|
31704
|
+
const decisionRecord = decisionRecordOfEvents(events);
|
|
31347
31705
|
const pipeline = input.pipeline ?? pipelineOfEvents(events);
|
|
31348
31706
|
const fitted = fitRecordToBudget({
|
|
31349
31707
|
id: run2.id,
|
|
@@ -31380,6 +31738,7 @@ function assembleRunRecord(input) {
|
|
|
31380
31738
|
...referencesOfEvents(events).length > 0 ? { references: referencesOfEvents(events) } : {},
|
|
31381
31739
|
...msg.sourceUrl !== void 0 ? { sourceUrl: msg.sourceUrl } : {},
|
|
31382
31740
|
...msg.userName !== void 0 ? { userName: msg.userName } : {},
|
|
31741
|
+
...input.headSha !== void 0 ? { headSha: input.headSha } : {},
|
|
31383
31742
|
...input.handoff !== void 0 ? { handoff: redactHandoff(input.handoff) } : {},
|
|
31384
31743
|
...input.verdict !== void 0 ? { verdict: redactVerdict(input.verdict) } : {},
|
|
31385
31744
|
...input.reviewHead !== void 0 ? { reviewHead: input.reviewHead } : {},
|
|
@@ -31391,6 +31750,7 @@ function assembleRunRecord(input) {
|
|
|
31391
31750
|
...input.parentRunId !== void 0 ? { parentRunId: input.parentRunId } : {},
|
|
31392
31751
|
...coordinatorFields(input.coordinator),
|
|
31393
31752
|
...instanceId !== void 0 ? { instanceId } : {},
|
|
31753
|
+
...decisionRecord !== void 0 ? decisionRecord : {},
|
|
31394
31754
|
...pipeline !== void 0 ? { pipeline } : {},
|
|
31395
31755
|
...input.hosted ? { hosted: true } : {},
|
|
31396
31756
|
...input.seed !== void 0 ? { seed: input.seed } : {},
|
|
@@ -31475,6 +31835,7 @@ function registerFinishRecord(deps, ctx) {
|
|
|
31475
31835
|
diagnosis,
|
|
31476
31836
|
root,
|
|
31477
31837
|
ledgerRun,
|
|
31838
|
+
headSha,
|
|
31478
31839
|
handoff,
|
|
31479
31840
|
verdict,
|
|
31480
31841
|
reviewHead,
|
|
@@ -31503,6 +31864,7 @@ function registerFinishRecord(deps, ctx) {
|
|
|
31503
31864
|
status: failedAfterFinish && status3 === "completed" ? "failed" : status3,
|
|
31504
31865
|
diagnosis,
|
|
31505
31866
|
seal,
|
|
31867
|
+
...headSha !== void 0 ? { headSha } : {},
|
|
31506
31868
|
...handoff !== void 0 ? { handoff } : {},
|
|
31507
31869
|
...verdict !== void 0 ? { verdict } : {},
|
|
31508
31870
|
...reviewHead !== void 0 ? { reviewHead } : {},
|
|
@@ -31845,6 +32207,7 @@ function createRunsService(deps) {
|
|
|
31845
32207
|
}
|
|
31846
32208
|
if (!row2) return {};
|
|
31847
32209
|
return {
|
|
32210
|
+
...row2.headSha !== void 0 ? { headSha: row2.headSha } : {},
|
|
31848
32211
|
...row2.verdict !== void 0 ? { verdict: row2.verdict } : {},
|
|
31849
32212
|
...row2.reviewHead !== void 0 ? { reviewHead: row2.reviewHead } : {},
|
|
31850
32213
|
...row2.reviewPost !== void 0 ? { reviewPost: row2.reviewPost } : {},
|
|
@@ -33509,6 +33872,9 @@ var init_instanceStore = __esm({
|
|
|
33509
33872
|
async listUnits(_instanceId) {
|
|
33510
33873
|
return [];
|
|
33511
33874
|
}
|
|
33875
|
+
async reserveDecisionRecord(_repo, _taskKey, _claimed, _existing) {
|
|
33876
|
+
return { ok: false, reason: "unavailable" };
|
|
33877
|
+
}
|
|
33512
33878
|
async markStopped(_instanceId, _at) {
|
|
33513
33879
|
return { ok: false, reason: "unavailable" };
|
|
33514
33880
|
}
|
|
@@ -33584,6 +33950,17 @@ var init_instanceStore = __esm({
|
|
|
33584
33950
|
throw new Error("coordinator store /runs/coordinator/units/list: the answer is not a list of unit rows");
|
|
33585
33951
|
return d.units;
|
|
33586
33952
|
}
|
|
33953
|
+
async reserveDecisionRecord(repo, taskKey, claimed2, existing) {
|
|
33954
|
+
const r = await this.post("/runs/decision-record/reserve", {
|
|
33955
|
+
repo,
|
|
33956
|
+
taskKey,
|
|
33957
|
+
claimed: [...claimed2],
|
|
33958
|
+
...existing !== void 0 ? { existing } : {}
|
|
33959
|
+
});
|
|
33960
|
+
const d = r.data;
|
|
33961
|
+
if (typeof d.number === "string" && /^\d{4}$/.test(d.number)) return { ok: true, number: d.number };
|
|
33962
|
+
throw new Error(`coordinator store /runs/decision-record/reserve: unexpected answer (HTTP ${r.status})`);
|
|
33963
|
+
}
|
|
33587
33964
|
async markStopped(instanceId, at) {
|
|
33588
33965
|
const r = await this.post("/runs/coordinator/stop", { instanceId, at });
|
|
33589
33966
|
const d = r.data;
|
|
@@ -33625,12 +34002,13 @@ var init_instanceStore = __esm({
|
|
|
33625
34002
|
function isIntakeReceipt(v) {
|
|
33626
34003
|
if (typeof v !== "object" || v === null) return false;
|
|
33627
34004
|
const r = v;
|
|
33628
|
-
return (r.verdict === "addressed" || r.verdict === "silent") && typeof r.reason === "string" && (r.source === "model" || r.source === "mode" || r.source === "question" || r.source === "error" || r.source === "timeout") && (r.mode === "mention" || r.mode === "classify") && typeof r.model === "string" && typeof r.gen === "number" && Number.isFinite(r.gen) && typeof r.threadKey === "string" && r.threadKey.length > 0 && r.threadKey.length <= 256 && typeof r.decidedAt === "number" && Number.isFinite(r.decidedAt);
|
|
34005
|
+
return (r.verdict === "addressed" || r.verdict === "silent") && typeof r.reason === "string" && (r.source === "model" || r.source === "mode" || r.source === "question" || r.source === "error" || r.source === "timeout") && (r.providerFailure === void 0 || typeof r.providerFailure === "string" && PROVIDER_FAILURE_CAUSES.includes(r.providerFailure)) && (r.mode === "mention" || r.mode === "classify") && typeof r.model === "string" && typeof r.gen === "number" && Number.isFinite(r.gen) && typeof r.threadKey === "string" && r.threadKey.length > 0 && r.threadKey.length <= 256 && typeof r.decidedAt === "number" && Number.isFinite(r.decidedAt);
|
|
33629
34006
|
}
|
|
33630
34007
|
var LEASE_MS, HEARTBEAT_MS, APPEND_FLUSH_MS, APPEND_FLUSH_EVENTS, TRANSCRIPT_REQUEST_BYTES, TRANSCRIPT_PART_BYTES, ATTACHMENT_REF_BYTES, GEN_PATTERN;
|
|
33631
34008
|
var init_types4 = __esm({
|
|
33632
34009
|
"../../src/core/runLedger/types.ts"() {
|
|
33633
34010
|
"use strict";
|
|
34011
|
+
init_provider();
|
|
33634
34012
|
LEASE_MS = 3e4;
|
|
33635
34013
|
HEARTBEAT_MS = 1e4;
|
|
33636
34014
|
APPEND_FLUSH_MS = 500;
|
|
@@ -34125,6 +34503,23 @@ var init_runLedgerWorker = __esm({
|
|
|
34125
34503
|
const r = await this.post("/runs/intake/read", { storeKey: this.opts.storeKey, key });
|
|
34126
34504
|
return isIntakeReceipt(r.data.receipt) ? r.data.receipt : void 0;
|
|
34127
34505
|
}
|
|
34506
|
+
async claimIntakeDelivery(key, poster, claimedAt) {
|
|
34507
|
+
const r = await this.post("/runs/intake/delivery/claim", {
|
|
34508
|
+
storeKey: this.opts.storeKey,
|
|
34509
|
+
key,
|
|
34510
|
+
poster,
|
|
34511
|
+
claimedAt
|
|
34512
|
+
});
|
|
34513
|
+
return r.data.claimed === true;
|
|
34514
|
+
}
|
|
34515
|
+
async finishIntakeDelivery(key, poster, delivered) {
|
|
34516
|
+
await this.post("/runs/intake/delivery/finish", {
|
|
34517
|
+
storeKey: this.opts.storeKey,
|
|
34518
|
+
key,
|
|
34519
|
+
poster,
|
|
34520
|
+
delivered
|
|
34521
|
+
});
|
|
34522
|
+
}
|
|
34128
34523
|
async listIntake(query) {
|
|
34129
34524
|
const r = await this.post("/runs/intake/list", {
|
|
34130
34525
|
storeKey: this.opts.storeKey,
|
|
@@ -34924,13 +35319,13 @@ var init_confirmations = __esm({
|
|
|
34924
35319
|
describe() {
|
|
34925
35320
|
return `state Worker ${this.baseUrl} (ConfigDO confirmations)`;
|
|
34926
35321
|
}
|
|
34927
|
-
async post(path,
|
|
35322
|
+
async post(path, payload2) {
|
|
34928
35323
|
let res;
|
|
34929
35324
|
try {
|
|
34930
35325
|
res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
34931
35326
|
method: "POST",
|
|
34932
35327
|
headers: { authorization: `Bearer ${this.opts.token}`, "content-type": "application/json" },
|
|
34933
|
-
body: JSON.stringify(
|
|
35328
|
+
body: JSON.stringify(payload2),
|
|
34934
35329
|
signal: AbortSignal.timeout(CONFIRMATION_WORKER_TIMEOUT_MS)
|
|
34935
35330
|
});
|
|
34936
35331
|
} catch (err2) {
|
|
@@ -35692,7 +36087,7 @@ async function openPrHeadSha(pr) {
|
|
|
35692
36087
|
}
|
|
35693
36088
|
async function currentPrHeadSha(pr) {
|
|
35694
36089
|
const head = await prHead(pr).catch(() => void 0);
|
|
35695
|
-
return head?.sha;
|
|
36090
|
+
return head?.state === "open" ? head.sha : void 0;
|
|
35696
36091
|
}
|
|
35697
36092
|
async function prCommitsSince(input) {
|
|
35698
36093
|
const sha = normalizeHead(input.sha);
|
|
@@ -36312,6 +36707,20 @@ async function runReviewPostStep(input) {
|
|
|
36312
36707
|
postTarget = null;
|
|
36313
36708
|
}
|
|
36314
36709
|
}
|
|
36710
|
+
if (input.guardTransition === true && postTarget && reviewHead) {
|
|
36711
|
+
const where = `${postTarget.repo}#${postTarget.number}`;
|
|
36712
|
+
const pinned = carried?.current ?? reviewHead;
|
|
36713
|
+
const facts2 = await input.fetchPrFacts({ repo: postTarget.repo, number: postTarget.number }).catch(() => void 0);
|
|
36714
|
+
const current = facts2?.state === "open" && facts2.headBranchExists === true ? normalizeHead(facts2.headSha) : void 0;
|
|
36715
|
+
if (current === void 0 || !sameCommit(current, pinned)) {
|
|
36716
|
+
const reason2 = current === void 0 ? "the pull request is no longer open at a readable head" : `the PR head moved to ${current.slice(0, 7)} after the review of ${pinned.slice(0, 7)}`;
|
|
36717
|
+
console.log(`[review-post] ${logKey} skipped: ${reason2} (${where})`);
|
|
36718
|
+
await input.reply(`\u2139\uFE0F Review not posted to ${where}: ${reason2} \u2014 this verdict is Slack-only.`).catch(() => {
|
|
36719
|
+
});
|
|
36720
|
+
skipReason = reason2;
|
|
36721
|
+
postTarget = null;
|
|
36722
|
+
}
|
|
36723
|
+
}
|
|
36315
36724
|
if (postTarget && reviewHead) {
|
|
36316
36725
|
const pinned = carried?.current ?? reviewHead;
|
|
36317
36726
|
const target = { ...postTarget, commitId: pinned };
|
|
@@ -36452,9 +36861,9 @@ function correctedMessage(msg, slug, match) {
|
|
|
36452
36861
|
}
|
|
36453
36862
|
async function onboardedGuess(deps, msg, slug) {
|
|
36454
36863
|
const list = deps.residentSlugs ?? residentSlugsLister(deps.config.config.execution?.resident);
|
|
36455
|
-
const
|
|
36456
|
-
if (!
|
|
36457
|
-
const near = nearMatch(slug,
|
|
36864
|
+
const candidates2 = await list?.().catch(() => void 0);
|
|
36865
|
+
if (!candidates2 || candidates2.length === 0) return void 0;
|
|
36866
|
+
const near = nearMatch(slug, candidates2);
|
|
36458
36867
|
if (!near.guess) return void 0;
|
|
36459
36868
|
const proposal = correctedMessage(msg, slug, near.guess);
|
|
36460
36869
|
if (!proposal) return void 0;
|
|
@@ -37766,6 +38175,12 @@ var init_statusCardFrame = __esm({
|
|
|
37766
38175
|
});
|
|
37767
38176
|
|
|
37768
38177
|
// ../../src/core/dispatch/route.ts
|
|
38178
|
+
function outputCapWithReasoning(visibleAnswerTokens, opts = {}) {
|
|
38179
|
+
return opts.capField !== void 0 && REASONING_COUNTING_CAP_FIELDS.has(opts.capField) ? visibleAnswerTokens + REASONING_OUTPUT_TOKEN_ALLOWANCE : visibleAnswerTokens;
|
|
38180
|
+
}
|
|
38181
|
+
function outputCapRetry(current) {
|
|
38182
|
+
return Math.max(current * 2, REASONING_OUTPUT_TOKEN_ALLOWANCE);
|
|
38183
|
+
}
|
|
37769
38184
|
function routedRunsAtOnce(def, confirm, input) {
|
|
37770
38185
|
const radius = input === void 0 ? blastRadius(def) : boundBlastRadius(def, input);
|
|
37771
38186
|
return radius === "read" || CONFIRM_ORDER[radius] < CONFIRM_ORDER[confirm];
|
|
@@ -37827,7 +38242,7 @@ function providerStructuredModel(provider, model, opts = {}) {
|
|
|
37827
38242
|
...opts.effort ? { effort: opts.effort.effort, effortWord: opts.effort.effortWord } : {},
|
|
37828
38243
|
...forced ? { tools, toolChoice } : {}
|
|
37829
38244
|
});
|
|
37830
|
-
if (result.stopReason === "max_tokens") throw new
|
|
38245
|
+
if (result.stopReason === "max_tokens") throw new OutputCapError(call2.maxTokens);
|
|
37831
38246
|
const calls = result.content.filter(
|
|
37832
38247
|
(p) => p.type === "tool_use"
|
|
37833
38248
|
);
|
|
@@ -37873,13 +38288,13 @@ function redactedInput(input) {
|
|
|
37873
38288
|
return v === void 0 ? null : text(JSON.stringify(v) ?? String(v));
|
|
37874
38289
|
};
|
|
37875
38290
|
const leafOrList = (v) => Array.isArray(v) ? v.map(leaf) : leaf(v);
|
|
37876
|
-
const
|
|
38291
|
+
const isRecord11 = (v) => typeof v === "object" && v !== null && (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
|
|
37877
38292
|
const entries = (v, of) => Object.fromEntries(
|
|
37878
38293
|
Object.entries(v).filter(([, x]) => x !== void 0).map(([k, x]) => [k, of(x)])
|
|
37879
38294
|
);
|
|
37880
38295
|
const object1 = (v) => entries(v, leafOrList);
|
|
37881
|
-
const object2 = (v) => entries(v, (x) =>
|
|
37882
|
-
const object3 = (v) => entries(v, (x) =>
|
|
38296
|
+
const object2 = (v) => entries(v, (x) => isRecord11(x) ? object1(x) : leafOrList(x));
|
|
38297
|
+
const object3 = (v) => entries(v, (x) => isRecord11(x) ? object2(x) : leafOrList(x));
|
|
37883
38298
|
return {
|
|
37884
38299
|
...input.args ? { args: input.args.map(leaf) } : {},
|
|
37885
38300
|
...input.options ? { options: object3(input.options) } : {}
|
|
@@ -37902,7 +38317,7 @@ function compoundBrief(text, parts) {
|
|
|
37902
38317
|
...parts.map((p, i) => `${i + 1}. \`${p.preset}\`: ${p.text}`)
|
|
37903
38318
|
].join("\n");
|
|
37904
38319
|
}
|
|
37905
|
-
var ROUTE_REASON_CAP, ROUTE_MIN_OUTPUT_TOKENS, ROUTE_TIMEOUT_MS, ROUTE_PART_LINE_CAP, ROUTE_RECEIPT_CAP, ROUTED_RECEIPT_PREFIX, COMPOUND_BRIEF_HEADING, MultiToolCallError;
|
|
38320
|
+
var REASONING_COUNTING_CAP_FIELDS, REASONING_OUTPUT_TOKEN_ALLOWANCE, OutputCapError, ROUTE_REASON_CAP, ROUTE_MIN_OUTPUT_TOKENS, ROUTE_TIMEOUT_MS, ROUTE_PART_LINE_CAP, ROUTE_RECEIPT_CAP, ROUTED_RECEIPT_PREFIX, COMPOUND_BRIEF_HEADING, MultiToolCallError;
|
|
37906
38321
|
var init_route = __esm({
|
|
37907
38322
|
"../../src/core/dispatch/route.ts"() {
|
|
37908
38323
|
"use strict";
|
|
@@ -37915,6 +38330,16 @@ var init_route = __esm({
|
|
|
37915
38330
|
init_commandSurface();
|
|
37916
38331
|
init_budgets();
|
|
37917
38332
|
init_confirmations();
|
|
38333
|
+
REASONING_COUNTING_CAP_FIELDS = /* @__PURE__ */ new Set(["max_tokens", "max_completion_tokens", "max_output_tokens"]);
|
|
38334
|
+
REASONING_OUTPUT_TOKEN_ALLOWANCE = 4096;
|
|
38335
|
+
OutputCapError = class extends Error {
|
|
38336
|
+
constructor(maxTokens) {
|
|
38337
|
+
super(`answer cut at the output cap (${maxTokens} tokens)`);
|
|
38338
|
+
this.maxTokens = maxTokens;
|
|
38339
|
+
this.name = "OutputCapError";
|
|
38340
|
+
}
|
|
38341
|
+
maxTokens;
|
|
38342
|
+
};
|
|
37918
38343
|
ROUTE_REASON_CAP = 120;
|
|
37919
38344
|
ROUTE_MIN_OUTPUT_TOKENS = 200;
|
|
37920
38345
|
ROUTE_TIMEOUT_MS = 8e3;
|
|
@@ -39421,11 +39846,12 @@ function resolveTarget2(deps, ctx) {
|
|
|
39421
39846
|
)
|
|
39422
39847
|
);
|
|
39423
39848
|
}
|
|
39424
|
-
|
|
39849
|
+
const harnessName = resolved.harness?.name ?? DEFAULT_HARNESS;
|
|
39850
|
+
if (modelCard.wire === "openai-responses" && harnessName === "opencode") {
|
|
39425
39851
|
throw new RefusalError(
|
|
39426
39852
|
refusalOf(
|
|
39427
39853
|
"model_card_refused",
|
|
39428
|
-
`
|
|
39854
|
+
`The "${harnessName}" harness cannot start model "${resolved.modelRef}" from provider "${providerName}": it cannot speak the "${modelCard.wire}" wire; this request needs the pi harness or an openai-chat block.`
|
|
39429
39855
|
)
|
|
39430
39856
|
);
|
|
39431
39857
|
}
|
|
@@ -40390,14 +40816,20 @@ function renderOperatorQuestion(decision) {
|
|
|
40390
40816
|
${OPERATOR_QUESTION_MARKER}
|
|
40391
40817
|
\`${decision.proposal}\`` : decision.text;
|
|
40392
40818
|
}
|
|
40393
|
-
function operatorMaxOutputTokens() {
|
|
40819
|
+
function operatorMaxOutputTokens(opts = {}) {
|
|
40394
40820
|
const chars = 2 * (ROUTE_RECEIPT_CAP + ROUTE_REASON_CAP + 40) + ROUTE_REASON_CAP + 80;
|
|
40395
|
-
return Math.ceil(chars / 3);
|
|
40821
|
+
return outputCapWithReasoning(Math.ceil(chars / 3), opts);
|
|
40822
|
+
}
|
|
40823
|
+
function promptWithoutTool(prompt, omitted) {
|
|
40824
|
+
const kept = [prompt.tool, ...prompt.tools ?? []].filter((candidate) => candidate.name !== omitted);
|
|
40825
|
+
const [tool, ...tools] = kept;
|
|
40826
|
+
if (tool === void 0) return void 0;
|
|
40827
|
+
return { ...prompt, tool, tools: tools.length > 0 ? tools : void 0 };
|
|
40396
40828
|
}
|
|
40397
40829
|
async function runOperator(input, model, opts = {}) {
|
|
40398
40830
|
const now = opts.now ?? Date.now;
|
|
40399
40831
|
const started = now();
|
|
40400
|
-
|
|
40832
|
+
let prompt = buildOperatorPrompt(input);
|
|
40401
40833
|
const ctx = {
|
|
40402
40834
|
requestText: input.text,
|
|
40403
40835
|
presets: input.projection.presets.map((p) => p.name),
|
|
@@ -40412,31 +40844,66 @@ async function runOperator(input, model, opts = {}) {
|
|
|
40412
40844
|
};
|
|
40413
40845
|
let chars = 0;
|
|
40414
40846
|
const attempts = [];
|
|
40415
|
-
const answered = (decision) => ({
|
|
40847
|
+
const answered = (decision, operatorDiagnostic) => ({
|
|
40416
40848
|
decision,
|
|
40417
40849
|
latencyMs: now() - started,
|
|
40418
40850
|
outputTokens: Math.ceil(chars / 3),
|
|
40851
|
+
...operatorDiagnostic !== void 0 ? { operatorDiagnostic } : {},
|
|
40419
40852
|
...attempts.length > 0 ? { attempts } : {}
|
|
40420
40853
|
});
|
|
40421
40854
|
const turns = [];
|
|
40422
40855
|
let reads = 0;
|
|
40423
40856
|
let violations = 0;
|
|
40857
|
+
let schemaReasks = 0;
|
|
40424
40858
|
let noCallTurns = 0;
|
|
40425
|
-
|
|
40426
|
-
|
|
40427
|
-
|
|
40428
|
-
|
|
40429
|
-
|
|
40430
|
-
return floor.kind === "decision" ? floor.decision : { kind: "non_decision", reason: "no_decision" };
|
|
40859
|
+
let outputCapCuts = 0;
|
|
40860
|
+
let maxOutputTokens = opts.maxOutputTokens ?? operatorMaxOutputTokens();
|
|
40861
|
+
const generalFloor = (reason2 = "no_decision") => {
|
|
40862
|
+
const floor = parseOperatorTurn({ tool: OPERATOR_BIND_TOOL, input: { preset: "general", reason: reason2 } }, ctx);
|
|
40863
|
+
return floor.kind === "decision" ? floor.decision : { kind: "non_decision", reason: reason2 };
|
|
40431
40864
|
};
|
|
40432
40865
|
const signal2 = AbortSignal.timeout(opts.timeoutMs ?? OPERATOR_TIMEOUT_MS);
|
|
40433
40866
|
try {
|
|
40434
40867
|
for (; ; ) {
|
|
40435
40868
|
let answer;
|
|
40436
40869
|
try {
|
|
40437
|
-
answer = await model({ ...prompt, retries: turns }, { maxTokens:
|
|
40870
|
+
answer = await model({ ...prompt, retries: turns }, { maxTokens: maxOutputTokens, signal: signal2 });
|
|
40438
40871
|
} catch (err2) {
|
|
40439
|
-
if (
|
|
40872
|
+
if (err2 instanceof OutputCapError) {
|
|
40873
|
+
const violation2 = err2.message;
|
|
40874
|
+
attempts.push({ outcome: "violation", violation: violation2 });
|
|
40875
|
+
if (outputCapCuts++ === 0) {
|
|
40876
|
+
turns.push({ answer: "", violation: `${violation2}; retry with the larger output allowance` });
|
|
40877
|
+
maxOutputTokens = outputCapRetry(maxOutputTokens);
|
|
40878
|
+
continue;
|
|
40879
|
+
}
|
|
40880
|
+
return answered(generalFloor("output_cap"));
|
|
40881
|
+
}
|
|
40882
|
+
if (!(err2 instanceof MultiToolCallError)) {
|
|
40883
|
+
const carried = attemptsOfThrow(err2);
|
|
40884
|
+
if (carried) attempts.push(...carried);
|
|
40885
|
+
const failure2 = providerFailureOf(err2);
|
|
40886
|
+
const rejected = failure2.cause === "request-rejected" && failure2.status === 400 ? failure2.schemaRejection : void 0;
|
|
40887
|
+
const offered = rejected !== void 0 && [prompt.tool, ...prompt.tools ?? []].some((candidate) => candidate.name === rejected.tool);
|
|
40888
|
+
const retry = offered && rejected !== void 0 && schemaReasks < OPERATOR_SCHEMA_REASKS_MAX ? promptWithoutTool(prompt, rejected.tool) : void 0;
|
|
40889
|
+
if (rejected !== void 0 && retry !== void 0) {
|
|
40890
|
+
const violation2 = `provider rejected tool "${rejected.tool}" schema keyword "${rejected.keyword}"; re-asked without that tool`;
|
|
40891
|
+
attempts.push({ outcome: "violation", violation: violation2 });
|
|
40892
|
+
schemaReasks++;
|
|
40893
|
+
prompt = retry;
|
|
40894
|
+
continue;
|
|
40895
|
+
}
|
|
40896
|
+
return answered(
|
|
40897
|
+
{
|
|
40898
|
+
kind: "refusal",
|
|
40899
|
+
cause: "provider",
|
|
40900
|
+
providerFailure: failure2.cause,
|
|
40901
|
+
reason: failure2.cause,
|
|
40902
|
+
text: renderProviderFailure(failure2.cause, "ended")
|
|
40903
|
+
},
|
|
40904
|
+
failure2.message
|
|
40905
|
+
);
|
|
40906
|
+
}
|
|
40440
40907
|
const calls = JSON.stringify(err2.calls);
|
|
40441
40908
|
chars += calls.length;
|
|
40442
40909
|
const violation = `the answer carried ${err2.calls.length} tool calls; one tool call per turn`;
|
|
@@ -40517,6 +40984,7 @@ function operatorEventOf(mode, answer, intake) {
|
|
|
40517
40984
|
...d.kind === "question" ? { question: renderOperatorQuestion(d) } : {},
|
|
40518
40985
|
...d.kind === "question" && d.proposal !== void 0 ? { proposal: d.proposal } : {},
|
|
40519
40986
|
...d.kind === "refusal" ? { refusalCause: d.cause, refusalText: d.text } : {},
|
|
40987
|
+
...d.kind === "refusal" && d.cause === "provider" ? { providerFailure: d.providerFailure } : {},
|
|
40520
40988
|
...answer.attempts ? { attempts: answer.attempts } : {},
|
|
40521
40989
|
...intake ? { intake: { verdict: intake.verdict, reason: intake.reason } } : {},
|
|
40522
40990
|
latencyMs: answer.latencyMs,
|
|
@@ -40558,6 +41026,7 @@ async function operatorStage(deps, ctx) {
|
|
|
40558
41026
|
const { msg, mode } = ctx;
|
|
40559
41027
|
const cfg = deps.config.config;
|
|
40560
41028
|
let model = deps.operatorModel;
|
|
41029
|
+
let maxOutputTokens;
|
|
40561
41030
|
if (!model) {
|
|
40562
41031
|
const modelRef3 = cfg.defaults.models["general"];
|
|
40563
41032
|
if (!modelRef3 || !deps.completions) {
|
|
@@ -40568,6 +41037,8 @@ async function operatorStage(deps, ctx) {
|
|
|
40568
41037
|
const ref = parseModelRef(modelRef3);
|
|
40569
41038
|
const effort2 = turnEffort(modelRef3, cfg.defaults.efforts?.["general"], cfg.providers);
|
|
40570
41039
|
if (effort2.note) console.log(`[operator] ${msg.threadKey} effort: ${effort2.note}`);
|
|
41040
|
+
const card = resolveModelCard(modelRef3, cfg.providers, installedModelRegistry);
|
|
41041
|
+
maxOutputTokens = operatorMaxOutputTokens({ capField: card.capField });
|
|
40571
41042
|
model = providerStructuredModel(deps.completions.get(ref.provider), ref.model, {
|
|
40572
41043
|
...effort2.request ? { effort: effort2.request } : {}
|
|
40573
41044
|
});
|
|
@@ -40605,8 +41076,11 @@ async function operatorStage(deps, ctx) {
|
|
|
40605
41076
|
...pending2 ? { pendingQuestion: pending2.proposal !== void 0 ? { proposal: pending2.proposal } : {} } : {},
|
|
40606
41077
|
...ctx.owner ? { owner: ctx.owner } : {}
|
|
40607
41078
|
},
|
|
40608
|
-
model
|
|
41079
|
+
model,
|
|
41080
|
+
maxOutputTokens !== void 0 ? { maxOutputTokens } : {}
|
|
40609
41081
|
);
|
|
41082
|
+
if (answer.operatorDiagnostic !== void 0)
|
|
41083
|
+
console.log(`[operator] ${msg.threadKey} provider refusal: ${answer.operatorDiagnostic}`);
|
|
40610
41084
|
const event = operatorEventOf(mode, answer, ctx.intake);
|
|
40611
41085
|
return event.outcome === "question" ? { ...event, request: redactAndCap(oneLine(msg.text), OPERATOR_REQUEST_CAP) } : event;
|
|
40612
41086
|
}
|
|
@@ -40637,6 +41111,12 @@ async function executeOperatorDecision(deps, ctx) {
|
|
|
40637
41111
|
await recordOperatorDecision(deps, msg, event, ctx.ending, ctx.trace);
|
|
40638
41112
|
return answered;
|
|
40639
41113
|
}
|
|
41114
|
+
if (event.providerFailure !== void 0) {
|
|
41115
|
+
io.requestFailed?.();
|
|
41116
|
+
await io.reply(event.refusalText ?? renderProviderFailure(event.providerFailure, "ended"));
|
|
41117
|
+
await recordOperatorDecision(deps, msg, event, ctx.ending, ctx.trace);
|
|
41118
|
+
return answered;
|
|
41119
|
+
}
|
|
40640
41120
|
if (ctx.owner !== void 0 && !ownedDecisionRuns(event, ctx.owner, deps.commands)) {
|
|
40641
41121
|
const confirmed = (event.binds ?? []).find((b) => b.confirmed);
|
|
40642
41122
|
const request2 = confirmed !== void 0 ? presetBindOf(
|
|
@@ -40735,7 +41215,7 @@ async function executeOperatorDecision(deps, ctx) {
|
|
|
40735
41215
|
if (!carried) await recordOperatorDecision(deps, msg, event, ctx.ending, ctx.trace);
|
|
40736
41216
|
return answered;
|
|
40737
41217
|
}
|
|
40738
|
-
var OPERATOR_BIND_TOOL, OPERATOR_ASK_TOOL, OPERATOR_READ_TOOLS, OPERATOR_READS_MAX, OPERATOR_TIMEOUT_MS, OPERATOR_QUESTION_MARKER, OPERATOR_REQUEST_CAP;
|
|
41218
|
+
var OPERATOR_BIND_TOOL, OPERATOR_ASK_TOOL, OPERATOR_READ_TOOLS, OPERATOR_READS_MAX, OPERATOR_SCHEMA_REASKS_MAX, OPERATOR_TIMEOUT_MS, OPERATOR_QUESTION_MARKER, OPERATOR_REQUEST_CAP;
|
|
40739
41219
|
var init_operator = __esm({
|
|
40740
41220
|
"../../src/core/dispatch/operator.ts"() {
|
|
40741
41221
|
"use strict";
|
|
@@ -40761,6 +41241,8 @@ var init_operator = __esm({
|
|
|
40761
41241
|
init_seed();
|
|
40762
41242
|
init_turnEffort();
|
|
40763
41243
|
init_thread();
|
|
41244
|
+
init_modelCard();
|
|
41245
|
+
init_installedModelRegistry();
|
|
40764
41246
|
init_route();
|
|
40765
41247
|
OPERATOR_BIND_TOOL = "bind_preset";
|
|
40766
41248
|
OPERATOR_ASK_TOOL = "ask";
|
|
@@ -40774,6 +41256,7 @@ var init_operator = __esm({
|
|
|
40774
41256
|
providerModels: "provider_models"
|
|
40775
41257
|
};
|
|
40776
41258
|
OPERATOR_READS_MAX = 4;
|
|
41259
|
+
OPERATOR_SCHEMA_REASKS_MAX = 4;
|
|
40777
41260
|
OPERATOR_TIMEOUT_MS = 2e4;
|
|
40778
41261
|
OPERATOR_QUESTION_MARKER = "Did you mean:";
|
|
40779
41262
|
OPERATOR_REQUEST_CAP = 600;
|
|
@@ -41406,6 +41889,8 @@ async function registerRun(deps, ctx) {
|
|
|
41406
41889
|
seed,
|
|
41407
41890
|
seedTurns,
|
|
41408
41891
|
agentSource,
|
|
41892
|
+
decisionRecord,
|
|
41893
|
+
decisionRecordTask,
|
|
41409
41894
|
modelCard,
|
|
41410
41895
|
cardDecisions,
|
|
41411
41896
|
route: route2
|
|
@@ -41504,6 +41989,8 @@ async function registerRun(deps, ctx) {
|
|
|
41504
41989
|
agent: agent.name,
|
|
41505
41990
|
agentSource,
|
|
41506
41991
|
model: resolved.modelRef,
|
|
41992
|
+
...decisionRecord !== void 0 ? { record: decisionRecord } : {},
|
|
41993
|
+
...decisionRecordTask !== void 0 ? { recordTaskKey: decisionRecordTask } : {},
|
|
41507
41994
|
traceId: root.traceId,
|
|
41508
41995
|
// The harness the run is driven by (harness.md items 8 and 10): the
|
|
41509
41996
|
// object the scopes' word for the preset picks off the roster — the
|
|
@@ -41570,6 +42057,8 @@ async function reserveRun(deps, ctx) {
|
|
|
41570
42057
|
parentRunId,
|
|
41571
42058
|
coordinator,
|
|
41572
42059
|
seed,
|
|
42060
|
+
decisionRecord,
|
|
42061
|
+
decisionRecordTask,
|
|
41573
42062
|
route: route2
|
|
41574
42063
|
} = ctx;
|
|
41575
42064
|
if (!resume && !restart) {
|
|
@@ -41593,6 +42082,8 @@ async function reserveRun(deps, ctx) {
|
|
|
41593
42082
|
...msg.authenticatedAs !== void 0 ? { authenticatedAs: msg.authenticatedAs } : {},
|
|
41594
42083
|
...msg.postedBy !== void 0 ? { postedBy: msg.postedBy } : {},
|
|
41595
42084
|
...resolved.effort !== void 0 ? { effort: resolved.effort } : {},
|
|
42085
|
+
...decisionRecord !== void 0 ? { record: decisionRecord } : {},
|
|
42086
|
+
...decisionRecordTask !== void 0 ? { recordTaskKey: decisionRecordTask } : {},
|
|
41596
42087
|
...repoCtx.ref !== void 0 ? { ref: repoCtx.ref } : {},
|
|
41597
42088
|
...repoCtx.headSha !== void 0 ? { headSha: repoCtx.headSha } : {},
|
|
41598
42089
|
...repoCtx.pr !== void 0 ? { pr: repoCtx.pr } : {},
|
|
@@ -42149,13 +42640,13 @@ function unquotePath(raw) {
|
|
|
42149
42640
|
}
|
|
42150
42641
|
function riskReasons(entry, paths) {
|
|
42151
42642
|
const reasons = [];
|
|
42152
|
-
const
|
|
42153
|
-
const any = (re) =>
|
|
42643
|
+
const candidates2 = [...new Set(paths.filter(Boolean))];
|
|
42644
|
+
const any = (re) => candidates2.some((p) => re.test(p));
|
|
42154
42645
|
if (any(MIGRATION_RE)) reasons.push("migration/schema");
|
|
42155
42646
|
if (any(AUTH_RE)) reasons.push("auth/permission-sensitive");
|
|
42156
42647
|
if (any(INFRA_RE)) reasons.push("infra/deploy config");
|
|
42157
42648
|
if (entry.status === "deleted") reasons.push("whole-file deletion");
|
|
42158
|
-
if (
|
|
42649
|
+
if (candidates2.some((p) => LOCKFILES.has(basename2(p).toLowerCase()))) reasons.push("lockfile");
|
|
42159
42650
|
const churn = entry.adds + entry.dels;
|
|
42160
42651
|
if (churn >= LARGE_CHURN) reasons.push(`large change (${churn} lines)`);
|
|
42161
42652
|
return reasons;
|
|
@@ -45202,6 +45693,103 @@ var init_run2 = __esm({
|
|
|
45202
45693
|
}
|
|
45203
45694
|
});
|
|
45204
45695
|
|
|
45696
|
+
// ../../src/core/decisionRecordReservation.ts
|
|
45697
|
+
function asksForDecisionRecord(text) {
|
|
45698
|
+
const marker = RECORD_MARKER.exec(text)?.[1]?.toLowerCase();
|
|
45699
|
+
if (marker !== void 0) return marker === "write" || marker === "yes" || marker === "true";
|
|
45700
|
+
for (const instruction of text.matchAll(POSITIVE_RECORD_INSTRUCTION)) {
|
|
45701
|
+
const sentenceStart = Math.max(
|
|
45702
|
+
text.lastIndexOf("\n", instruction.index),
|
|
45703
|
+
text.lastIndexOf(".", instruction.index),
|
|
45704
|
+
text.lastIndexOf("!", instruction.index),
|
|
45705
|
+
text.lastIndexOf("?", instruction.index),
|
|
45706
|
+
text.lastIndexOf(";", instruction.index)
|
|
45707
|
+
);
|
|
45708
|
+
const beforeVerb = text.slice(sentenceStart + 1, instruction.index);
|
|
45709
|
+
if (!NEGATED_INSTRUCTION.test(beforeVerb)) return true;
|
|
45710
|
+
}
|
|
45711
|
+
return false;
|
|
45712
|
+
}
|
|
45713
|
+
function decisionRecordTaskKey(...parts) {
|
|
45714
|
+
let hash = 0xcbf29ce484222325n;
|
|
45715
|
+
for (const byte of new TextEncoder().encode(parts.join("\n"))) {
|
|
45716
|
+
hash ^= BigInt(byte);
|
|
45717
|
+
hash = BigInt.asUintN(64, hash * 0x100000001b3n);
|
|
45718
|
+
}
|
|
45719
|
+
return hash.toString(16).padStart(16, "0");
|
|
45720
|
+
}
|
|
45721
|
+
var DECISION_RECORD_ENV, RECORD_MARKER, POSITIVE_RECORD_INSTRUCTION, NEGATED_INSTRUCTION, DECISION_RECORD_STORE_REFUSAL, DecisionRecordReservationUnavailableError, DecisionRecordAllocator;
|
|
45722
|
+
var init_decisionRecordReservation = __esm({
|
|
45723
|
+
"../../src/core/decisionRecordReservation.ts"() {
|
|
45724
|
+
"use strict";
|
|
45725
|
+
DECISION_RECORD_ENV = "SWITCHBOARD_DECISION_RECORD";
|
|
45726
|
+
RECORD_MARKER = /(?:^|\n)\s*(?:-\s*)?(?:\*\*)?(?:decision[- ]record|record)(?:\*\*)?\s*:\s*(write|yes|true|none|no|false)\b/im;
|
|
45727
|
+
POSITIVE_RECORD_INSTRUCTION = /\b(?:write|draft|create|add|author|produce|document)\b[^\n.!?;]{0,160}\b(?:technical\s+|architectural\s+|architecture\s+)?decision[- ]record\b/gi;
|
|
45728
|
+
NEGATED_INSTRUCTION = /(?:\b(?:do|does|did|must|should|will|can)\s+not(?:\s+\w+){0,3}|\b(?:don't|doesn't|didn't|mustn't|shouldn't|won't|can't)(?:\s+\w+){0,3}|\b(?:never|not|without)(?:\s+\w+){0,3})\s*$/i;
|
|
45729
|
+
DECISION_RECORD_STORE_REFUSAL = "\u26A0\uFE0F A record-writing task needs the durable coordinator store on the state Worker (`runHistory.worker`), but that store is unavailable, so no number was issued and nothing ran.";
|
|
45730
|
+
DecisionRecordReservationUnavailableError = class extends Error {
|
|
45731
|
+
constructor() {
|
|
45732
|
+
super("the durable coordinator store is unavailable");
|
|
45733
|
+
this.name = "DecisionRecordReservationUnavailableError";
|
|
45734
|
+
}
|
|
45735
|
+
};
|
|
45736
|
+
DecisionRecordAllocator = class {
|
|
45737
|
+
constructor(claims, durable) {
|
|
45738
|
+
this.claims = claims;
|
|
45739
|
+
this.durable = durable;
|
|
45740
|
+
}
|
|
45741
|
+
claims;
|
|
45742
|
+
durable;
|
|
45743
|
+
byTask = /* @__PURE__ */ new Map();
|
|
45744
|
+
claimed = /* @__PURE__ */ new Map();
|
|
45745
|
+
tails = /* @__PURE__ */ new Map();
|
|
45746
|
+
async reserve(repo, taskKey, existing) {
|
|
45747
|
+
const cacheKey = `${repo}
|
|
45748
|
+
${taskKey}`;
|
|
45749
|
+
const cached = this.byTask.get(cacheKey);
|
|
45750
|
+
if (cached !== void 0) return cached;
|
|
45751
|
+
const previous = this.tails.get(repo) ?? Promise.resolve();
|
|
45752
|
+
let release;
|
|
45753
|
+
const tail = new Promise((resolve13) => {
|
|
45754
|
+
release = resolve13;
|
|
45755
|
+
});
|
|
45756
|
+
const queued = previous.then(() => tail);
|
|
45757
|
+
this.tails.set(repo, queued);
|
|
45758
|
+
await previous;
|
|
45759
|
+
try {
|
|
45760
|
+
const repeated = this.byTask.get(cacheKey);
|
|
45761
|
+
if (repeated !== void 0) return repeated;
|
|
45762
|
+
const used = new Set(await this.claims(repo));
|
|
45763
|
+
for (const number2 of this.claimedFor(repo)) used.add(number2);
|
|
45764
|
+
const prior = existing;
|
|
45765
|
+
const durable = await this.durable?.(repo, taskKey, used, prior);
|
|
45766
|
+
if (this.durable !== void 0 && durable === void 0) throw new DecisionRecordReservationUnavailableError();
|
|
45767
|
+
if (durable !== void 0 && !/^\d{4}$/.test(durable))
|
|
45768
|
+
throw new Error(`decision-record reservation store returned invalid number ${JSON.stringify(durable)}`);
|
|
45769
|
+
if (prior !== void 0 && durable !== void 0 && durable !== prior)
|
|
45770
|
+
throw new Error(`decision-record reservation store returned ${durable} for task already carrying ${prior}`);
|
|
45771
|
+
const highest = [...used].reduce((max, value) => /^\d{4}$/.test(value) ? Math.max(max, Number(value)) : max, 0);
|
|
45772
|
+
const number = durable ?? prior ?? String(highest + 1).padStart(4, "0");
|
|
45773
|
+
this.byTask.set(cacheKey, number);
|
|
45774
|
+
this.claimedFor(repo).add(number);
|
|
45775
|
+
return number;
|
|
45776
|
+
} finally {
|
|
45777
|
+
release();
|
|
45778
|
+
if (this.tails.get(repo) === queued) this.tails.delete(repo);
|
|
45779
|
+
}
|
|
45780
|
+
}
|
|
45781
|
+
claimedFor(repo) {
|
|
45782
|
+
let set = this.claimed.get(repo);
|
|
45783
|
+
if (set === void 0) {
|
|
45784
|
+
set = /* @__PURE__ */ new Set();
|
|
45785
|
+
this.claimed.set(repo, set);
|
|
45786
|
+
}
|
|
45787
|
+
return set;
|
|
45788
|
+
}
|
|
45789
|
+
};
|
|
45790
|
+
}
|
|
45791
|
+
});
|
|
45792
|
+
|
|
45205
45793
|
// ../../src/core/harness/contract.ts
|
|
45206
45794
|
function harnessFactsOf(value) {
|
|
45207
45795
|
if (!isRecord4(value)) return void 0;
|
|
@@ -45211,7 +45799,7 @@ function harnessFactsOf(value) {
|
|
|
45211
45799
|
return void 0;
|
|
45212
45800
|
}
|
|
45213
45801
|
function piFactsOf(v) {
|
|
45214
|
-
const { harness: _harness, pid, logOffset, sessionFile, root, bearerHash, container, relaunches, ...rest } = v;
|
|
45802
|
+
const { harness: _harness, pid, logOffset, sessionFile, root, bearerHash, wire, container, relaunches, ...rest } = v;
|
|
45215
45803
|
if (typeof pid !== "number" || typeof logOffset !== "number") return void 0;
|
|
45216
45804
|
return {
|
|
45217
45805
|
...rest,
|
|
@@ -45222,6 +45810,7 @@ function piFactsOf(v) {
|
|
|
45222
45810
|
...typeof sessionFile === "string" ? { sessionFile } : {},
|
|
45223
45811
|
...typeof bearerHash === "string" ? { bearerHash } : {},
|
|
45224
45812
|
...typeof root === "string" ? { root } : {},
|
|
45813
|
+
...WIRES.includes(wire) ? { wire } : {},
|
|
45225
45814
|
...typeof container === "string" ? { container } : {}
|
|
45226
45815
|
};
|
|
45227
45816
|
}
|
|
@@ -45272,6 +45861,7 @@ var SAID_ONCE_SUFFIX, isRecord4, relaunchesOf, isPiFacts, HarnessInterruptedErro
|
|
|
45272
45861
|
var init_contract4 = __esm({
|
|
45273
45862
|
"../../src/core/harness/contract.ts"() {
|
|
45274
45863
|
"use strict";
|
|
45864
|
+
init_provider();
|
|
45275
45865
|
SAID_ONCE_SUFFIX = " (said once: later events of this kind are not noted)";
|
|
45276
45866
|
isRecord4 = (v) => typeof v === "object" && v !== null;
|
|
45277
45867
|
relaunchesOf = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0 ? v : 0;
|
|
@@ -46661,6 +47251,94 @@ var init_runBearers = __esm({
|
|
|
46661
47251
|
}
|
|
46662
47252
|
});
|
|
46663
47253
|
|
|
47254
|
+
// ../../src/core/modelProxy/providerFailureAuth.ts
|
|
47255
|
+
import { createHmac, randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
|
|
47256
|
+
function payload(envelope, nonce) {
|
|
47257
|
+
return JSON.stringify([
|
|
47258
|
+
AUTH_VERSION,
|
|
47259
|
+
nonce,
|
|
47260
|
+
envelope.type,
|
|
47261
|
+
envelope.cause,
|
|
47262
|
+
envelope.message,
|
|
47263
|
+
envelope.schemaRejection ?? null
|
|
47264
|
+
]);
|
|
47265
|
+
}
|
|
47266
|
+
function signature(envelope, nonce) {
|
|
47267
|
+
return createHmac("sha256", AUTH_KEY).update(payload(envelope, nonce)).digest();
|
|
47268
|
+
}
|
|
47269
|
+
function authenticateProxyProviderFailure(envelope) {
|
|
47270
|
+
const nonce = randomBytes5(NONCE_BYTES).toString("base64url");
|
|
47271
|
+
const mac = signature(envelope, nonce).toString("base64url");
|
|
47272
|
+
return { ...envelope, [PROXY_PROVIDER_FAILURE_AUTH_FIELD]: `${AUTH_VERSION}.${nonce}.${mac}` };
|
|
47273
|
+
}
|
|
47274
|
+
function parseBody2(value) {
|
|
47275
|
+
if (typeof value !== "string") return value;
|
|
47276
|
+
const text = value.trim();
|
|
47277
|
+
for (let at = text.indexOf("{"); at >= 0; at = text.indexOf("{", at + 1)) {
|
|
47278
|
+
try {
|
|
47279
|
+
return JSON.parse(text.slice(at));
|
|
47280
|
+
} catch {
|
|
47281
|
+
}
|
|
47282
|
+
}
|
|
47283
|
+
return void 0;
|
|
47284
|
+
}
|
|
47285
|
+
function candidates(value, into = []) {
|
|
47286
|
+
if (Array.isArray(value)) {
|
|
47287
|
+
for (const item of value) candidates(item, into);
|
|
47288
|
+
return into;
|
|
47289
|
+
}
|
|
47290
|
+
const row2 = isRecord5(value) ? value : void 0;
|
|
47291
|
+
if (!row2) return into;
|
|
47292
|
+
if (row2.type === "provider_failure") into.push(row2);
|
|
47293
|
+
for (const item of Object.values(row2)) candidates(item, into);
|
|
47294
|
+
return into;
|
|
47295
|
+
}
|
|
47296
|
+
function proxyProviderFailureIsAuthenticated(value) {
|
|
47297
|
+
const found = candidates(parseBody2(value));
|
|
47298
|
+
if (found.length !== 1) return false;
|
|
47299
|
+
const row2 = found[0];
|
|
47300
|
+
if (row2.type !== "provider_failure" || !isCause(row2.cause) || typeof row2.message !== "string") return false;
|
|
47301
|
+
const rejection = isRecord5(row2.schemaRejection) ? row2.schemaRejection : void 0;
|
|
47302
|
+
if (row2.schemaRejection !== void 0 && (typeof rejection?.tool !== "string" || rejection.tool.length === 0 || typeof rejection.keyword !== "string" || rejection.keyword.length === 0))
|
|
47303
|
+
return false;
|
|
47304
|
+
const schemaRejection = rejection !== void 0 ? { tool: rejection.tool, keyword: rejection.keyword } : void 0;
|
|
47305
|
+
const marker = row2[PROXY_PROVIDER_FAILURE_AUTH_FIELD];
|
|
47306
|
+
if (typeof marker !== "string") return false;
|
|
47307
|
+
const parts = marker.split(".");
|
|
47308
|
+
if (parts.length !== 3 || parts[0] !== AUTH_VERSION) return false;
|
|
47309
|
+
const [, nonce, encodedMac] = parts;
|
|
47310
|
+
if (!/^[A-Za-z0-9_-]{22}$/.test(nonce) || !/^[A-Za-z0-9_-]{43}$/.test(encodedMac)) return false;
|
|
47311
|
+
let offered;
|
|
47312
|
+
try {
|
|
47313
|
+
offered = Buffer.from(encodedMac, "base64url");
|
|
47314
|
+
} catch {
|
|
47315
|
+
return false;
|
|
47316
|
+
}
|
|
47317
|
+
const expected = signature(
|
|
47318
|
+
{
|
|
47319
|
+
type: "provider_failure",
|
|
47320
|
+
cause: row2.cause,
|
|
47321
|
+
message: row2.message,
|
|
47322
|
+
...schemaRejection !== void 0 ? { schemaRejection } : {}
|
|
47323
|
+
},
|
|
47324
|
+
nonce
|
|
47325
|
+
);
|
|
47326
|
+
return offered.length === expected.length && timingSafeEqual3(offered, expected);
|
|
47327
|
+
}
|
|
47328
|
+
var PROXY_PROVIDER_FAILURE_AUTH_FIELD, AUTH_VERSION, AUTH_KEY, NONCE_BYTES, isRecord5, isCause;
|
|
47329
|
+
var init_providerFailureAuth = __esm({
|
|
47330
|
+
"../../src/core/modelProxy/providerFailureAuth.ts"() {
|
|
47331
|
+
"use strict";
|
|
47332
|
+
init_provider();
|
|
47333
|
+
PROXY_PROVIDER_FAILURE_AUTH_FIELD = "_switchboard_proxy_auth";
|
|
47334
|
+
AUTH_VERSION = "v1";
|
|
47335
|
+
AUTH_KEY = randomBytes5(32);
|
|
47336
|
+
NONCE_BYTES = 16;
|
|
47337
|
+
isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
47338
|
+
isCause = (value) => typeof value === "string" && PROVIDER_FAILURE_CAUSES.includes(value);
|
|
47339
|
+
}
|
|
47340
|
+
});
|
|
47341
|
+
|
|
46664
47342
|
// ../../src/core/harness/pi/compactionFallback.ts
|
|
46665
47343
|
function compactionAskOf(body) {
|
|
46666
47344
|
if (typeof body !== "object" || body === null) return void 0;
|
|
@@ -46928,7 +47606,7 @@ export default async function switchboardHarness(pi) {
|
|
|
46928
47606
|
|
|
46929
47607
|
// ../../src/core/harness/pi/bridge.ts
|
|
46930
47608
|
function describePiToolCall(tool, args) {
|
|
46931
|
-
const input =
|
|
47609
|
+
const input = isRecord6(args) ? args : void 0;
|
|
46932
47610
|
if (tool === "bash" && typeof input?.command === "string") return `$ ${input.command}`;
|
|
46933
47611
|
for (const key of ["path", "name", "url", "query"]) {
|
|
46934
47612
|
const v = input?.[key];
|
|
@@ -46937,8 +47615,8 @@ function describePiToolCall(tool, args) {
|
|
|
46937
47615
|
return tool;
|
|
46938
47616
|
}
|
|
46939
47617
|
function piResultText(result) {
|
|
46940
|
-
const content =
|
|
46941
|
-
return content.filter((p) =>
|
|
47618
|
+
const content = isRecord6(result) && Array.isArray(result.content) ? result.content : [];
|
|
47619
|
+
return content.filter((p) => isRecord6(p) && p.type === "text" && typeof p.text === "string").map((p) => String(p.text)).join("\n");
|
|
46942
47620
|
}
|
|
46943
47621
|
function piBashExit(text, isError) {
|
|
46944
47622
|
const trailer = /Command exited with code (\d+)\s*$/.exec(text);
|
|
@@ -46947,12 +47625,14 @@ function piBashExit(text, isError) {
|
|
|
46947
47625
|
if (prefixed.failed) return prefixed;
|
|
46948
47626
|
return isError ? { failed: true } : { failed: false, exitCode: 0 };
|
|
46949
47627
|
}
|
|
46950
|
-
var PI_EVENT_DISPOSITION, DIALOG_METHODS, BOOKKEEPING_TOOL, POLICY_REFUSAL_STOP_REASONS,
|
|
47628
|
+
var PI_EVENT_DISPOSITION, DIALOG_METHODS, BOOKKEEPING_TOOL, POLICY_REFUSAL_STOP_REASONS, isRecord6, str6, PiBridge;
|
|
46951
47629
|
var init_bridge2 = __esm({
|
|
46952
47630
|
"../../src/core/harness/pi/bridge.ts"() {
|
|
46953
47631
|
"use strict";
|
|
46954
47632
|
init_formatDuration();
|
|
46955
47633
|
init_runEvents();
|
|
47634
|
+
init_providerFailureAuth();
|
|
47635
|
+
init_provider();
|
|
46956
47636
|
init_contract4();
|
|
46957
47637
|
init_windDown();
|
|
46958
47638
|
init_compactionFallback();
|
|
@@ -46986,7 +47666,7 @@ var init_bridge2 = __esm({
|
|
|
46986
47666
|
DIALOG_METHODS = /* @__PURE__ */ new Set(["select", "confirm", "input", "editor"]);
|
|
46987
47667
|
BOOKKEEPING_TOOL = "update_status";
|
|
46988
47668
|
POLICY_REFUSAL_STOP_REASONS = /* @__PURE__ */ new Set(["refusal", "sensitive", "content_filter"]);
|
|
46989
|
-
|
|
47669
|
+
isRecord6 = (v) => typeof v === "object" && v !== null;
|
|
46990
47670
|
str6 = (v) => typeof v === "string" ? v : String(v ?? "");
|
|
46991
47671
|
PiBridge = class {
|
|
46992
47672
|
constructor(deps) {
|
|
@@ -47080,10 +47760,10 @@ var init_bridge2 = __esm({
|
|
|
47080
47760
|
this.modelCallOpen = true;
|
|
47081
47761
|
break;
|
|
47082
47762
|
case "message_start":
|
|
47083
|
-
if (
|
|
47763
|
+
if (isRecord6(event.message) && event.message.role === "assistant") this.assistantStartedAt = this.deps.clock();
|
|
47084
47764
|
break;
|
|
47085
47765
|
case "message_end":
|
|
47086
|
-
if (
|
|
47766
|
+
if (isRecord6(event.message)) {
|
|
47087
47767
|
if (event.message.role === "assistant") {
|
|
47088
47768
|
const assistant = event.message;
|
|
47089
47769
|
this.onAssistant(assistant, out);
|
|
@@ -47146,14 +47826,19 @@ var init_bridge2 = __esm({
|
|
|
47146
47826
|
this.assistantStartedAt = void 0;
|
|
47147
47827
|
}
|
|
47148
47828
|
if (message4.stopReason === "error") {
|
|
47149
|
-
|
|
47829
|
+
const raw = message4.errorMessage ?? "the model call failed";
|
|
47830
|
+
out.providerFailure = classifyProviderFailure({
|
|
47831
|
+
error: raw,
|
|
47832
|
+
trustedEnvelope: proxyProviderFailureIsAuthenticated(raw)
|
|
47833
|
+
});
|
|
47834
|
+
out.providerError = redactAndCap(raw, 400);
|
|
47150
47835
|
if (typeof message4.rawStopReason === "string" && POLICY_REFUSAL_STOP_REASONS.has(message4.rawStopReason))
|
|
47151
47836
|
out.policyRefusal = true;
|
|
47152
47837
|
return;
|
|
47153
47838
|
}
|
|
47154
47839
|
const content = Array.isArray(message4.content) ? message4.content : [];
|
|
47155
|
-
const toolCalls = content.filter((b) =>
|
|
47156
|
-
const text = content.filter((b) =>
|
|
47840
|
+
const toolCalls = content.filter((b) => isRecord6(b) && b.type === "toolCall");
|
|
47841
|
+
const text = content.filter((b) => isRecord6(b) && b.type === "text" && typeof b.text === "string").map((b) => String(b.text)).join("\n").trim();
|
|
47157
47842
|
if (toolCalls.length === 0) {
|
|
47158
47843
|
if (text) this.narrateHeld();
|
|
47159
47844
|
this.answerText = text || this.heldAnswer || "";
|
|
@@ -47173,7 +47858,7 @@ var init_bridge2 = __esm({
|
|
|
47173
47858
|
const span = this.agentSpan?.start(`tool.${tool}`);
|
|
47174
47859
|
this.openTools.set(callId, { span, tool, judged: this.judgeGate });
|
|
47175
47860
|
this.toolCalls++;
|
|
47176
|
-
const input =
|
|
47861
|
+
const input = isRecord6(event.args) ? event.args : void 0;
|
|
47177
47862
|
const command2 = tool === "bash" && typeof input?.command === "string" ? { command: redactAndCap(input.command, COMMAND_CAP) } : {};
|
|
47178
47863
|
const bound = tool === "bash" && typeof input?.timeout === "number" && Number.isFinite(input.timeout) && input.timeout > 0 ? { boundMs: Math.round(input.timeout * 1e3) } : {};
|
|
47179
47864
|
this.emit({
|
|
@@ -47231,7 +47916,7 @@ var init_bridge2 = __esm({
|
|
|
47231
47916
|
}
|
|
47232
47917
|
}
|
|
47233
47918
|
onCompactionEnd(event, out) {
|
|
47234
|
-
const result =
|
|
47919
|
+
const result = isRecord6(event.result) ? event.result : void 0;
|
|
47235
47920
|
if (event.aborted === true || !result) {
|
|
47236
47921
|
const why = typeof event.errorMessage === "string" ? event.errorMessage : void 0;
|
|
47237
47922
|
this.note(
|
|
@@ -47750,7 +48435,7 @@ var init_reattach = __esm({
|
|
|
47750
48435
|
// ../../src/core/harness/pi/mirror.ts
|
|
47751
48436
|
import { isDeepStrictEqual } from "node:util";
|
|
47752
48437
|
function boundOf(input) {
|
|
47753
|
-
if (!
|
|
48438
|
+
if (!isRecord7(input)) return {};
|
|
47754
48439
|
const t = input.timeout;
|
|
47755
48440
|
return typeof t === "number" && Number.isFinite(t) && t > 0 ? { boundMs: secondsToMs(t) } : {};
|
|
47756
48441
|
}
|
|
@@ -47759,7 +48444,7 @@ function partsOf2(content) {
|
|
|
47759
48444
|
if (!Array.isArray(content)) return [];
|
|
47760
48445
|
const parts = [];
|
|
47761
48446
|
for (const block of content) {
|
|
47762
|
-
if (!
|
|
48447
|
+
if (!isRecord7(block)) continue;
|
|
47763
48448
|
if (block.type === "text" && typeof block.text === "string") parts.push({ type: "text", text: block.text });
|
|
47764
48449
|
else if (block.type === "image" && typeof block.data === "string")
|
|
47765
48450
|
parts.push({ type: "image", mediaType: String(block.mimeType ?? "image/png"), data: block.data });
|
|
@@ -47838,7 +48523,7 @@ function piSessionFile(messages, opts, compactions = []) {
|
|
|
47838
48523
|
if (p.type === "text") content.push({ type: "text", text: p.text });
|
|
47839
48524
|
else if (p.type === "tool_use") {
|
|
47840
48525
|
toolNames.set(p.id, p.name);
|
|
47841
|
-
content.push({ type: "toolCall", id: p.id, name: p.name, arguments:
|
|
48526
|
+
content.push({ type: "toolCall", id: p.id, name: p.name, arguments: isRecord7(p.input) ? p.input : {} });
|
|
47842
48527
|
}
|
|
47843
48528
|
}
|
|
47844
48529
|
const hasTool = content.some((b) => b.type === "toolCall");
|
|
@@ -47894,12 +48579,12 @@ function sessionIdOf(at) {
|
|
|
47894
48579
|
const hex = at.toString(16).padStart(12, "0").slice(-12);
|
|
47895
48580
|
return `00000000-0000-4000-8000-${hex}`;
|
|
47896
48581
|
}
|
|
47897
|
-
var
|
|
48582
|
+
var isRecord7, PiMirror;
|
|
47898
48583
|
var init_mirror = __esm({
|
|
47899
48584
|
"../../src/core/harness/pi/mirror.ts"() {
|
|
47900
48585
|
"use strict";
|
|
47901
48586
|
init_budgets();
|
|
47902
|
-
|
|
48587
|
+
isRecord7 = (v) => typeof v === "object" && v !== null;
|
|
47903
48588
|
PiMirror = class {
|
|
47904
48589
|
constructor(deps) {
|
|
47905
48590
|
this.deps = deps;
|
|
@@ -48108,6 +48793,7 @@ function piLaunchArgs(spec) {
|
|
|
48108
48793
|
}
|
|
48109
48794
|
function piLaunchEnv(spec, bearer) {
|
|
48110
48795
|
return {
|
|
48796
|
+
...spec.environment,
|
|
48111
48797
|
[RUN_BEARER_ENV]: bearer,
|
|
48112
48798
|
[HARNESS_URL_ENV]: spec.harnessUrl,
|
|
48113
48799
|
SWITCHBOARD_RUN_ID: spec.runId,
|
|
@@ -48277,15 +48963,15 @@ function piStreamOptions(api, req, key) {
|
|
|
48277
48963
|
if (api === "openai-responses") return { ...shared, toolChoice: { type: "function", name: req.toolChoice.name } };
|
|
48278
48964
|
return { ...shared, toolChoice: { type: "function", function: { name: req.toolChoice.name } } };
|
|
48279
48965
|
}
|
|
48280
|
-
function anthropicParallelOff(
|
|
48281
|
-
const p =
|
|
48966
|
+
function anthropicParallelOff(payload2) {
|
|
48967
|
+
const p = payload2;
|
|
48282
48968
|
return {
|
|
48283
|
-
...
|
|
48969
|
+
...payload2,
|
|
48284
48970
|
tool_choice: { ...p.tool_choice, disable_parallel_tool_use: true }
|
|
48285
48971
|
};
|
|
48286
48972
|
}
|
|
48287
|
-
function openAiParallelOff(
|
|
48288
|
-
return { ...
|
|
48973
|
+
function openAiParallelOff(payload2) {
|
|
48974
|
+
return { ...payload2, parallel_tool_calls: false };
|
|
48289
48975
|
}
|
|
48290
48976
|
function toPiContext(req, model, clock4) {
|
|
48291
48977
|
const callNames = /* @__PURE__ */ new Map();
|
|
@@ -48378,9 +49064,18 @@ function visiblePart(part) {
|
|
|
48378
49064
|
return void 0;
|
|
48379
49065
|
}
|
|
48380
49066
|
}
|
|
48381
|
-
function fromPiMessage(message4, provider) {
|
|
49067
|
+
function fromPiMessage(message4, provider, tools) {
|
|
48382
49068
|
if (message4.stopReason === "error" || message4.stopReason === "aborted") {
|
|
48383
|
-
|
|
49069
|
+
const raw = message4.errorMessage ?? "the model call failed";
|
|
49070
|
+
const failure2 = classifyProviderFailure({ error: raw, provider, model: message4.model });
|
|
49071
|
+
const schemaRejection = failure2.cause === "request-rejected" && failure2.status === 400 ? providerSchemaRejectionOf(raw, tools) : void 0;
|
|
49072
|
+
throw new ProviderFailure(failure2.cause, {
|
|
49073
|
+
...failure2.status !== void 0 ? { status: failure2.status } : {},
|
|
49074
|
+
...failure2.provider !== void 0 ? { provider: failure2.provider } : {},
|
|
49075
|
+
...failure2.model !== void 0 ? { model: failure2.model } : {},
|
|
49076
|
+
...failure2.operatorUrl !== void 0 ? { operatorUrl: failure2.operatorUrl } : {},
|
|
49077
|
+
...schemaRejection !== void 0 ? { schemaRejection } : {}
|
|
49078
|
+
});
|
|
48384
49079
|
}
|
|
48385
49080
|
const content = [];
|
|
48386
49081
|
for (const part of message4.content) {
|
|
@@ -48481,7 +49176,12 @@ var init_piAi = __esm({
|
|
|
48481
49176
|
let key;
|
|
48482
49177
|
if (this.keyEnv !== void 0) {
|
|
48483
49178
|
const secret2 = this.secrets.named(this.keyEnv);
|
|
48484
|
-
if (!secret2)
|
|
49179
|
+
if (!secret2)
|
|
49180
|
+
throw new ProviderFailure("key-absent", {
|
|
49181
|
+
provider: this.name,
|
|
49182
|
+
model: req.model,
|
|
49183
|
+
keyVariable: this.keyEnv
|
|
49184
|
+
});
|
|
48485
49185
|
key = secret2.reveal();
|
|
48486
49186
|
}
|
|
48487
49187
|
const model = this.model(req.model, req.maxTokens, req.effort !== void 0);
|
|
@@ -48489,8 +49189,21 @@ var init_piAi = __esm({
|
|
|
48489
49189
|
...piStreamOptions(this.api, req, key),
|
|
48490
49190
|
...this.fetchImpl ? { fetch: this.fetchImpl } : {}
|
|
48491
49191
|
};
|
|
48492
|
-
|
|
48493
|
-
|
|
49192
|
+
try {
|
|
49193
|
+
const message4 = await this.api$().stream(model, toPiContext(req, model, this.clock), options).result();
|
|
49194
|
+
return fromPiMessage(message4, this.name, req.tools);
|
|
49195
|
+
} catch (err2) {
|
|
49196
|
+
const failure2 = providerFailureOf(err2);
|
|
49197
|
+
const schemaRejection = failure2.schemaRejection ?? (failure2.cause === "request-rejected" && failure2.status === 400 ? providerSchemaRejectionOf(err2, req.tools) : void 0);
|
|
49198
|
+
throw new ProviderFailure(failure2.cause, {
|
|
49199
|
+
...failure2.status !== void 0 ? { status: failure2.status } : {},
|
|
49200
|
+
provider: this.name,
|
|
49201
|
+
model: req.model,
|
|
49202
|
+
...failure2.operatorUrl !== void 0 ? { operatorUrl: failure2.operatorUrl } : {},
|
|
49203
|
+
...schemaRejection !== void 0 ? { schemaRejection } : {},
|
|
49204
|
+
...failure2.keyVariable !== void 0 ? { keyVariable: failure2.keyVariable } : failure2.cause === "key-invalid" && this.keyEnv !== void 0 ? { keyVariable: this.keyEnv } : {}
|
|
49205
|
+
});
|
|
49206
|
+
}
|
|
48494
49207
|
}
|
|
48495
49208
|
/** pi's implementation of this provider's API, loaded on the first call and
|
|
48496
49209
|
* kept; a scripted one stands in for it in tests. */
|
|
@@ -48593,7 +49306,7 @@ function judgeToolCall(tool, input, ctx) {
|
|
|
48593
49306
|
ctx.identity === "none" ? `${tool} is the \`${bundle}\` bundle: a run without a workspace (identity none) has none of pi's own tools` : `${tool} is the \`${bundle}\` bundle, outside the ${ctx.identity} identity's reach`
|
|
48594
49307
|
);
|
|
48595
49308
|
}
|
|
48596
|
-
const args =
|
|
49309
|
+
const args = isRecord8(input) ? input : {};
|
|
48597
49310
|
if (tool === "bash") return judgeBash(args.command, args.timeout, ctx);
|
|
48598
49311
|
if (bundle === "files" || bundle === "write-files") return judgePath(args.path, ctx);
|
|
48599
49312
|
return allowed;
|
|
@@ -48671,7 +49384,7 @@ function judgePath(path, ctx) {
|
|
|
48671
49384
|
if (rel.startsWith("..") || isAbsolute5(rel)) return refused4(`path \u2014 \`${path}\` resolves outside the checkout`);
|
|
48672
49385
|
return allowed;
|
|
48673
49386
|
}
|
|
48674
|
-
var PI_TOOL_BUNDLES, CODING_REACH, READ_REACH, NONE_REACH, allowed, refused4, outside,
|
|
49387
|
+
var PI_TOOL_BUNDLES, CODING_REACH, READ_REACH, NONE_REACH, allowed, refused4, outside, isRecord8, CREDENTIAL_FILE, ENV_DUMP, CREDENTIAL_VAR, MERGE_OR_APPROVE, GIT_THEN_PUSH, GIT_PUSH, ANY_PUSH, GH_WRITE_VERB, WRITE_METHOD, GH_API_WRITE, CURL_GITHUB_WRITE, OPENCODE_ACTION_TO_TOOL_WORD, REDIRECTION;
|
|
48675
49388
|
var init_toolRules = __esm({
|
|
48676
49389
|
"../../src/core/harness/pi/toolRules.ts"() {
|
|
48677
49390
|
"use strict";
|
|
@@ -48701,7 +49414,7 @@ var init_toolRules = __esm({
|
|
|
48701
49414
|
allowed = { verdict: "allowed" };
|
|
48702
49415
|
refused4 = (reason2) => ({ verdict: "refused", reason: reason2 });
|
|
48703
49416
|
outside = (reason2) => ({ verdict: "outside-profile", reason: reason2 });
|
|
48704
|
-
|
|
49417
|
+
isRecord8 = (v) => typeof v === "object" && v !== null;
|
|
48705
49418
|
CREDENTIAL_FILE = /(^|[\s/'"`])(\.git\/)?(github-credentials|\.git-credentials)($|[\s'"`|;&])/;
|
|
48706
49419
|
ENV_DUMP = /(^|[;&|(]\s*)((printenv|env)(\s+-[A-Za-z0-9-]+)*|export\s+-p|declare\s+-[a-zA-Z]*[px][a-zA-Z]*|set)\s*($|[|;&>)])|\/proc\/(self|\d+)\/environ|process\.env(?![.[\w])/;
|
|
48707
49420
|
CREDENTIAL_VAR = /\$\{?[A-Z][A-Z0-9_]*(_API_KEY|_TOKEN|_SECRET|_BEARER|_PASSWORD)\b|printenv\s+[A-Z][A-Z0-9_]*(_API_KEY|_TOKEN|_SECRET|_BEARER|_PASSWORD)\b/;
|
|
@@ -48987,13 +49700,6 @@ async function locatePi(facts2, container, here) {
|
|
|
48987
49700
|
function isAbortedProviderError(message4) {
|
|
48988
49701
|
return /\baborted\b/i.test(message4);
|
|
48989
49702
|
}
|
|
48990
|
-
function isTransientProviderError(message4) {
|
|
48991
|
-
return /stream ended before message_stop|stream ended without finish_reason|ended before completion/i.test(message4) || /^(?:AbortError:\s*)?(?:This|The) operation was aborted\.?$/i.test(message4.trim()) || /ECONNRESET|ETIMEDOUT|EPIPE|socket hang up|fetch failed|other side closed|network (error|failure)|(connection|stream) (reset|closed|terminated)|timed? ?out/i.test(
|
|
48992
|
-
message4
|
|
48993
|
-
) || /^terminated$/i.test(message4.trim()) || /overloaded/i.test(message4) || /^\s*(408|425|429|5\d\d)\b/.test(message4) || /<html[\s>][\s\S]{0,4000}\b(?:bad gateway|service unavailable|gateway timeout)\b/i.test(message4) || /(?:\bhttp\b[^a-z0-9]{0,8}|\bstatus(?: code)?\b[^0-9]{0,5}|\berror\b[^0-9]{0,5}|\bapi error\b[^0-9]{0,5})(408|425|429|5\d\d)\b/i.test(
|
|
48994
|
-
message4
|
|
48995
|
-
);
|
|
48996
|
-
}
|
|
48997
49703
|
function piStartFailureOf(err2) {
|
|
48998
49704
|
if (!(err2 instanceof HarnessContainerError) || err2.operation !== "send") return void 0;
|
|
48999
49705
|
const timeout = err2.message.match(/exit 124:.*?(\d+)s command timeout/i);
|
|
@@ -49075,6 +49781,7 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
49075
49781
|
const { container, clock: clock4 } = deps;
|
|
49076
49782
|
const now = () => clock4();
|
|
49077
49783
|
const recorded = run2.resume?.facts;
|
|
49784
|
+
const runWire = piRunWire({ model: { providerType: run2.model.providerType }, card: run2.card });
|
|
49078
49785
|
if (recorded !== void 0 && !isPiFacts(recorded)) {
|
|
49079
49786
|
const mismatch = new HarnessMismatchError("pi", recorded.harness);
|
|
49080
49787
|
run2.onProgress?.(mismatch.message);
|
|
@@ -49092,13 +49799,9 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
49092
49799
|
run2.onProgress?.(summary);
|
|
49093
49800
|
emit({ type: "run_note", kind, summary, ...mode ? { mode } : {} });
|
|
49094
49801
|
};
|
|
49095
|
-
const policyRefused = (
|
|
49096
|
-
emit({
|
|
49097
|
-
|
|
49098
|
-
kind: "policy_refusal",
|
|
49099
|
-
summary: `the model refused the call under the provider's usage policy: ${explanation}`
|
|
49100
|
-
});
|
|
49101
|
-
return new ModelPolicyRefusedError(explanation);
|
|
49802
|
+
const policyRefused = (failure2) => {
|
|
49803
|
+
emit({ type: "run_note", kind: "policy_refusal", summary: renderProviderFailure(failure2.cause, "parked") });
|
|
49804
|
+
return new ModelPolicyRefusedError(failure2);
|
|
49102
49805
|
};
|
|
49103
49806
|
const bridge = new PiBridge({
|
|
49104
49807
|
emit,
|
|
@@ -49298,11 +50001,12 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
49298
50001
|
if (located2 === "another-container") {
|
|
49299
50002
|
elsewhere = `pi is elsewhere: the row's pi (pid ${recorded.pid}) ran in container ${recorded.container}, not the one this run was handed (${here}), so it was neither probed nor ended here`;
|
|
49300
50003
|
} else if (located2 === "alive-here") {
|
|
49301
|
-
|
|
50004
|
+
const wireMismatch = recorded.wire !== void 0 && recorded.wire !== runWire ? `was configured for ${recorded.wire} while provider ${run2.model.provider} now declares ${runWire}` : void 0;
|
|
50005
|
+
if (recorded.root !== void 0 && wireMismatch === void 0 && honoured(recorded.bearerHash)) {
|
|
49302
50006
|
reattached = true;
|
|
49303
50007
|
paths = piRunPathsAt(recorded.root);
|
|
49304
50008
|
} else {
|
|
49305
|
-
ended = recorded.root === void 0 ? "named no directory for its pi" : "carried no bearer this generation could honour for its pi";
|
|
50009
|
+
ended = recorded.root === void 0 ? "named no directory for its pi" : wireMismatch ?? "carried no bearer this generation could honour for its pi";
|
|
49306
50010
|
await container.kill(recorded.pid).catch(() => {
|
|
49307
50011
|
});
|
|
49308
50012
|
}
|
|
@@ -49310,7 +50014,11 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
49310
50014
|
}
|
|
49311
50015
|
if (reattached && recorded && paths !== void 0) {
|
|
49312
50016
|
pid = recorded.pid;
|
|
49313
|
-
facts2 = {
|
|
50017
|
+
facts2 = {
|
|
50018
|
+
...recorded,
|
|
50019
|
+
wire: runWire,
|
|
50020
|
+
...recorded.container === void 0 && here !== void 0 ? { container: here } : {}
|
|
50021
|
+
};
|
|
49314
50022
|
mirrored = recorded.logOffset;
|
|
49315
50023
|
transport = new PiRpcTransport({
|
|
49316
50024
|
container,
|
|
@@ -49341,6 +50049,7 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
49341
50049
|
...run2.effort ? { effort: run2.effort } : {},
|
|
49342
50050
|
identity: run2.agent.identity,
|
|
49343
50051
|
system: run2.system,
|
|
50052
|
+
...run2.environment !== void 0 ? { environment: run2.environment } : {},
|
|
49344
50053
|
relayTools: run2.tools.map((t) => t.name),
|
|
49345
50054
|
...deps.compaction ? { compaction: deps.compaction } : {}
|
|
49346
50055
|
};
|
|
@@ -49389,7 +50098,7 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
49389
50098
|
model: {
|
|
49390
50099
|
provider: run2.model.provider,
|
|
49391
50100
|
id: run2.model.id,
|
|
49392
|
-
api: piApiFor(
|
|
50101
|
+
api: piApiFor(runWire)
|
|
49393
50102
|
},
|
|
49394
50103
|
at: now()
|
|
49395
50104
|
},
|
|
@@ -49434,6 +50143,7 @@ async function runPiHarnessOpen(deps, run2) {
|
|
|
49434
50143
|
logOffset: 0,
|
|
49435
50144
|
root: paths.dir,
|
|
49436
50145
|
...bearerHash !== void 0 ? { bearerHash } : {},
|
|
50146
|
+
wire: runWire,
|
|
49437
50147
|
...here !== void 0 ? { container: here } : {},
|
|
49438
50148
|
relaunches: recorded?.relaunches ?? 0
|
|
49439
50149
|
};
|
|
@@ -49760,7 +50470,7 @@ ${stagedLine}` : prompt;
|
|
|
49760
50470
|
for (const command2 of unsent) sends.send(command2);
|
|
49761
50471
|
return outcome;
|
|
49762
50472
|
};
|
|
49763
|
-
let
|
|
50473
|
+
let providerFailure;
|
|
49764
50474
|
let providerRefusal = false;
|
|
49765
50475
|
let providerRetries = 0;
|
|
49766
50476
|
let containerSaid;
|
|
@@ -49866,7 +50576,7 @@ ${stagedLine}` : prompt;
|
|
|
49866
50576
|
}
|
|
49867
50577
|
if (obs.message?.role === "user") steerEchoed(obs.message);
|
|
49868
50578
|
if (obs.message && await mirror.onMessage(obs.message, bridge.turns)) held2();
|
|
49869
|
-
if (obs.compactionFailed !== void 0 && !
|
|
50579
|
+
if (obs.compactionFailed !== void 0 && !providerFailureParks(classifyProviderFailure({ error: obs.compactionFailed }).cause)) {
|
|
49870
50580
|
compactionFailure = obs.compactionFailed;
|
|
49871
50581
|
if (!catchingUp && run2.onCompactionFailed) {
|
|
49872
50582
|
try {
|
|
@@ -49898,27 +50608,31 @@ ${stagedLine}` : prompt;
|
|
|
49898
50608
|
}
|
|
49899
50609
|
}
|
|
49900
50610
|
if (obs.providerError !== void 0) {
|
|
50611
|
+
const failure2 = obs.providerFailure ?? providerFailureOf(obs.providerError);
|
|
49901
50612
|
if (catchingUp)
|
|
49902
|
-
note(
|
|
50613
|
+
note(
|
|
50614
|
+
"harness_error",
|
|
50615
|
+
`a model call failed while the bot was away (${renderProviderFailure(failure2.cause, "parked")}); continuing`
|
|
50616
|
+
);
|
|
49903
50617
|
else if (cutAborted && !finaleAborted && isAbortedProviderError(obs.providerError)) {
|
|
49904
50618
|
cutAborted = false;
|
|
49905
|
-
} else if (obs.policyRefusal !== true && !writeUp && !finaleAborted &&
|
|
49906
|
-
heldTurn =
|
|
50619
|
+
} else if (obs.policyRefusal !== true && !writeUp && !finaleAborted && providerFailureParks(failure2.cause)) {
|
|
50620
|
+
heldTurn = failure2;
|
|
49907
50621
|
parkSettled = false;
|
|
49908
50622
|
const backoff = PROVIDER_RETRY_BACKOFFS_MS[Math.min(providerRetries, PROVIDER_RETRY_BACKOFFS_MS.length - 1)];
|
|
49909
50623
|
run2.onProgress?.(
|
|
49910
50624
|
`the model provider did not complete the call; the turn is held and retry ${providerRetries + 1} waits ${backoff / 1e3}s inside this run's lease`
|
|
49911
50625
|
);
|
|
49912
50626
|
} else if (writeUp || finaleAborted) {
|
|
49913
|
-
writeUpFailed =
|
|
49914
|
-
note("harness_error", windDownFailureNote(
|
|
50627
|
+
writeUpFailed = renderProviderFailure(failure2.cause, "parked");
|
|
50628
|
+
note("harness_error", windDownFailureNote(writeUpFailed));
|
|
49915
50629
|
} else {
|
|
49916
|
-
|
|
50630
|
+
providerFailure = failure2;
|
|
49917
50631
|
providerRefusal = obs.policyRefusal === true;
|
|
49918
50632
|
}
|
|
49919
50633
|
}
|
|
49920
50634
|
if (obs.settled && !catchingUp) {
|
|
49921
|
-
if (heldTurn !== void 0 &&
|
|
50635
|
+
if (heldTurn !== void 0 && providerFailure === void 0 && !hardStopped && !writeUp && !finaleAborted) {
|
|
49922
50636
|
parkSettled = true;
|
|
49923
50637
|
if (providerRetryWait === void 0) {
|
|
49924
50638
|
const backoff = PROVIDER_RETRY_BACKOFFS_MS[Math.min(providerRetries, PROVIDER_RETRY_BACKOFFS_MS.length - 1)];
|
|
@@ -50010,12 +50724,10 @@ ${stagedLine}` : prompt;
|
|
|
50010
50724
|
answer = HARD_STOP_MESSAGE;
|
|
50011
50725
|
} else {
|
|
50012
50726
|
if (bypass) throw bypass;
|
|
50013
|
-
if (
|
|
50014
|
-
if (providerRefusal) throw policyRefused(
|
|
50015
|
-
if (
|
|
50016
|
-
throw
|
|
50017
|
-
providerRetries > 0 ? `the model call failed after ${providerRetries} ${providerRetries === 1 ? "retry" : "retries"}: ${providerError}` : `the model call failed: ${providerError}`
|
|
50018
|
-
);
|
|
50727
|
+
if (providerFailure !== void 0) {
|
|
50728
|
+
if (providerRefusal) throw policyRefused(providerFailure);
|
|
50729
|
+
if (providerFailureParks(providerFailure.cause)) throw new ModelTransientFailureError(PROVIDER_RETRY_EXHAUSTED);
|
|
50730
|
+
throw providerFailure;
|
|
50019
50731
|
}
|
|
50020
50732
|
const text = bridge.answer() ?? "";
|
|
50021
50733
|
ending = windDownEndingOf(writeUp ?? (stopMode === "soft" ? { kind: "soft" } : void 0), text, writeUpFailed);
|
|
@@ -50050,7 +50762,57 @@ ${stagedLine}` : prompt;
|
|
|
50050
50762
|
writeUpFailed = void 0;
|
|
50051
50763
|
const id = `${ids.prompt}:follow-up:${++followUps}`;
|
|
50052
50764
|
let turnSettled = false;
|
|
50053
|
-
let
|
|
50765
|
+
let turnFailure;
|
|
50766
|
+
let turnHeld;
|
|
50767
|
+
let turnParkSettled = false;
|
|
50768
|
+
let turnRetryReady = false;
|
|
50769
|
+
let turnRetryWait;
|
|
50770
|
+
let turnRetryGeneration = 0;
|
|
50771
|
+
let turnRetries = 0;
|
|
50772
|
+
let turnRetryInFlight;
|
|
50773
|
+
let turnReissueInFlight;
|
|
50774
|
+
let turnReissues = 0;
|
|
50775
|
+
let turnReissueRows = [];
|
|
50776
|
+
let turnReissueInFlightRows = [];
|
|
50777
|
+
const clearTurnProviderHold = () => {
|
|
50778
|
+
turnHeld = void 0;
|
|
50779
|
+
turnParkSettled = false;
|
|
50780
|
+
turnRetryReady = false;
|
|
50781
|
+
turnRetryWait = void 0;
|
|
50782
|
+
turnRetryGeneration += 1;
|
|
50783
|
+
turnReissueRows = [];
|
|
50784
|
+
turnReissueInFlightRows = [];
|
|
50785
|
+
};
|
|
50786
|
+
const maybeReissueTurn = () => {
|
|
50787
|
+
if (turnHeld === void 0 || !turnParkSettled || turnReissueInFlight !== void 0 || turnRetryInFlight !== void 0 || turnReissueRows.length === 0 || hardStopped || writeUp !== void 0 || finaleAborted)
|
|
50788
|
+
return;
|
|
50789
|
+
turnReissues += 1;
|
|
50790
|
+
turnReissueInFlight = turnReissues === 1 ? `${id}:reissue` : `${id}:reissue:${turnReissues}`;
|
|
50791
|
+
turnReissueInFlightRows = turnReissueRows.splice(0);
|
|
50792
|
+
turnParkSettled = false;
|
|
50793
|
+
turnSettled = false;
|
|
50794
|
+
sends.send({ id: turnReissueInFlight, type: "prompt", message: REISSUE_PROMPT });
|
|
50795
|
+
};
|
|
50796
|
+
const drainTurnReissues = () => {
|
|
50797
|
+
const inputs = run2.inbox?.drain() ?? [];
|
|
50798
|
+
if (inputs.length === 0) {
|
|
50799
|
+
maybeReissueTurn();
|
|
50800
|
+
return;
|
|
50801
|
+
}
|
|
50802
|
+
const reissued = inputs.filter((item) => item.userId === PLANE_ACTOR_ID && isReissueSteerText(item.text));
|
|
50803
|
+
const waiting2 = reissued.length === 0 ? inputs : inputs.filter((item) => !reissued.includes(item));
|
|
50804
|
+
if (waiting2.length > 0) run2.inbox?.requeue(waiting2);
|
|
50805
|
+
for (const item of reissued) {
|
|
50806
|
+
emit({
|
|
50807
|
+
type: "input",
|
|
50808
|
+
text: redactSecrets(item.text),
|
|
50809
|
+
messageId: followUpMessageId(item),
|
|
50810
|
+
...item.userName ? { source: { user: item.userName } } : {}
|
|
50811
|
+
});
|
|
50812
|
+
}
|
|
50813
|
+
turnReissueRows.push(...reissued);
|
|
50814
|
+
maybeReissueTurn();
|
|
50815
|
+
};
|
|
50054
50816
|
let turnRefusal = false;
|
|
50055
50817
|
let turnFailed = false;
|
|
50056
50818
|
const turnCheck = () => {
|
|
@@ -50068,6 +50830,19 @@ ${stagedLine}` : prompt;
|
|
|
50068
50830
|
}
|
|
50069
50831
|
return;
|
|
50070
50832
|
}
|
|
50833
|
+
drainTurnReissues();
|
|
50834
|
+
if (turnHeld !== void 0) {
|
|
50835
|
+
if (now() >= turnDeadline) throw new ModelTransientFailureError(PROVIDER_RETRY_EXHAUSTED);
|
|
50836
|
+
if (turnParkSettled && turnRetryReady && turnRetryInFlight === void 0 && turnReissueInFlight === void 0) {
|
|
50837
|
+
turnRetryReady = false;
|
|
50838
|
+
turnRetryWait = void 0;
|
|
50839
|
+
turnRetries += 1;
|
|
50840
|
+
turnRetryInFlight = turnRetries === 1 ? `${id}:retry` : `${id}:retry:${turnRetries}`;
|
|
50841
|
+
turnParkSettled = false;
|
|
50842
|
+
turnSettled = false;
|
|
50843
|
+
sends.send({ id: turnRetryInFlight, type: "prompt", message: PROVIDER_RETRY_PROMPT });
|
|
50844
|
+
}
|
|
50845
|
+
}
|
|
50071
50846
|
if (run2.control?.requested === "soft") {
|
|
50072
50847
|
note("stopped", softStopNote(), "soft");
|
|
50073
50848
|
startWriteUp({ kind: "soft" }, SOFT_STOP_INSTRUCTION);
|
|
@@ -50135,19 +50910,69 @@ ${stagedLine}` : prompt;
|
|
|
50135
50910
|
abortPi();
|
|
50136
50911
|
break;
|
|
50137
50912
|
}
|
|
50138
|
-
if (obs.response)
|
|
50913
|
+
if (obs.response) {
|
|
50914
|
+
noteEcho(obs.response);
|
|
50915
|
+
if (turnReissueInFlight !== void 0 && obs.response.id === turnReissueInFlight) {
|
|
50916
|
+
turnReissueInFlight = void 0;
|
|
50917
|
+
if (obs.response.success === false) {
|
|
50918
|
+
turnReissueRows.unshift(...turnReissueInFlightRows);
|
|
50919
|
+
turnReissueInFlightRows = [];
|
|
50920
|
+
turnParkSettled = false;
|
|
50921
|
+
note(
|
|
50922
|
+
"harness_error",
|
|
50923
|
+
`the follow-up turn's reissue prompt was refused (${String(obs.response.error ?? "no reason")}); the turn stays held for the next settle`
|
|
50924
|
+
);
|
|
50925
|
+
} else {
|
|
50926
|
+
mirror.inboxConsumedSeq = Math.max(
|
|
50927
|
+
mirror.inboxConsumedSeq,
|
|
50928
|
+
...turnReissueInFlightRows.map((item) => item.ledgerSeq ?? 0)
|
|
50929
|
+
);
|
|
50930
|
+
clearTurnProviderHold();
|
|
50931
|
+
}
|
|
50932
|
+
}
|
|
50933
|
+
if (turnRetryInFlight !== void 0 && obs.response.id === turnRetryInFlight) {
|
|
50934
|
+
turnRetryInFlight = void 0;
|
|
50935
|
+
if (obs.response.success === false) {
|
|
50936
|
+
turnParkSettled = false;
|
|
50937
|
+
note("harness_error", "the follow-up turn's model retry prompt was refused; the failure remains held");
|
|
50938
|
+
} else clearTurnProviderHold();
|
|
50939
|
+
}
|
|
50940
|
+
}
|
|
50139
50941
|
if (obs.response?.id === id && obs.response.success === false)
|
|
50140
50942
|
throw new PromptRefused(String(obs.response.error ?? "no reason"));
|
|
50141
50943
|
if (obs.providerError !== void 0) {
|
|
50944
|
+
const failure2 = obs.providerFailure ?? providerFailureOf(obs.providerError);
|
|
50142
50945
|
if (writeUp || finaleAborted) {
|
|
50143
|
-
writeUpFailed =
|
|
50144
|
-
note("harness_error", windDownFailureNote(
|
|
50946
|
+
writeUpFailed = renderProviderFailure(failure2.cause, "parked");
|
|
50947
|
+
note("harness_error", windDownFailureNote(writeUpFailed, "turn"));
|
|
50948
|
+
} else if (obs.policyRefusal !== true && providerFailureParks(failure2.cause)) {
|
|
50949
|
+
turnHeld = failure2;
|
|
50950
|
+
turnFailure = void 0;
|
|
50951
|
+
turnRefusal = false;
|
|
50952
|
+
turnParkSettled = false;
|
|
50953
|
+
const backoff = PROVIDER_RETRY_BACKOFFS_MS[Math.min(turnRetries, PROVIDER_RETRY_BACKOFFS_MS.length - 1)];
|
|
50954
|
+
run2.onProgress?.(
|
|
50955
|
+
`the model provider did not complete the follow-up call; the turn is held and retry ${turnRetries + 1} waits ${backoff / 1e3}s inside this run's lease`
|
|
50956
|
+
);
|
|
50145
50957
|
} else {
|
|
50146
|
-
|
|
50958
|
+
turnFailure = failure2;
|
|
50147
50959
|
turnRefusal = obs.policyRefusal === true;
|
|
50148
50960
|
}
|
|
50149
50961
|
}
|
|
50150
50962
|
if (obs.settled) {
|
|
50963
|
+
if (turnHeld !== void 0 && turnFailure === void 0 && !hardStopped && !writeUp && !finaleAborted) {
|
|
50964
|
+
turnParkSettled = true;
|
|
50965
|
+
if (turnRetryWait === void 0) {
|
|
50966
|
+
const backoff = PROVIDER_RETRY_BACKOFFS_MS[Math.min(turnRetries, PROVIDER_RETRY_BACKOFFS_MS.length - 1)];
|
|
50967
|
+
const generation = ++turnRetryGeneration;
|
|
50968
|
+
turnRetryWait = deps.sleep(backoff).then(() => {
|
|
50969
|
+
if (turnRetryGeneration === generation) turnRetryReady = true;
|
|
50970
|
+
});
|
|
50971
|
+
}
|
|
50972
|
+
turnCheck();
|
|
50973
|
+
if (hardStopped) break;
|
|
50974
|
+
continue;
|
|
50975
|
+
}
|
|
50151
50976
|
turnSettled = true;
|
|
50152
50977
|
break;
|
|
50153
50978
|
}
|
|
@@ -50205,9 +51030,9 @@ ${stagedLine}` : prompt;
|
|
|
50205
51030
|
`pi exited before the turn settled${tail2.trim() ? `: ${redactAndCap(tail2.trim(), 400)}` : ""}`
|
|
50206
51031
|
);
|
|
50207
51032
|
}
|
|
50208
|
-
if (
|
|
50209
|
-
if (turnRefusal) throw policyRefused(
|
|
50210
|
-
throw
|
|
51033
|
+
if (turnFailure !== void 0) {
|
|
51034
|
+
if (turnRefusal) throw policyRefused(turnFailure);
|
|
51035
|
+
throw turnFailure;
|
|
50211
51036
|
}
|
|
50212
51037
|
const text = bridge.answer() ?? "";
|
|
50213
51038
|
const turnEnding = windDownEndingOf(writeUp, text, writeUpFailed);
|
|
@@ -50217,6 +51042,7 @@ ${stagedLine}` : prompt;
|
|
|
50217
51042
|
if (err2 instanceof HarnessControlFileLostError) note("harness_error", err2.message);
|
|
50218
51043
|
throw err2;
|
|
50219
51044
|
} finally {
|
|
51045
|
+
turnRetryGeneration += 1;
|
|
50220
51046
|
deps.bearers?.clearTurn(run2.runId);
|
|
50221
51047
|
live.toolContext = runContext;
|
|
50222
51048
|
live.rules = rules;
|
|
@@ -50239,6 +51065,7 @@ var CALL_SEEN_WAIT_MS, CALL_SEEN_TICK_MS, PROVIDER_RETRY_PROMPT, REISSUE_PROMPT,
|
|
|
50239
51065
|
var init_harness = __esm({
|
|
50240
51066
|
"../../src/core/harness/pi/harness.ts"() {
|
|
50241
51067
|
"use strict";
|
|
51068
|
+
init_provider();
|
|
50242
51069
|
init_contract4();
|
|
50243
51070
|
init_windDown();
|
|
50244
51071
|
init_runBearers();
|
|
@@ -50286,14 +51113,14 @@ var init_harness = __esm({
|
|
|
50286
51113
|
this.name = "PiContainerReplacedError";
|
|
50287
51114
|
}
|
|
50288
51115
|
};
|
|
50289
|
-
POLICY_REFUSAL_REPLY = "
|
|
51116
|
+
POLICY_REFUSAL_REPLY = renderProviderFailure("permanent");
|
|
50290
51117
|
ModelPolicyRefusedError = class extends Error {
|
|
50291
|
-
constructor(
|
|
51118
|
+
constructor(providerFailure) {
|
|
50292
51119
|
super(POLICY_REFUSAL_REPLY);
|
|
50293
|
-
this.
|
|
51120
|
+
this.providerFailure = providerFailure;
|
|
50294
51121
|
this.name = "ModelPolicyRefusedError";
|
|
50295
51122
|
}
|
|
50296
|
-
|
|
51123
|
+
providerFailure;
|
|
50297
51124
|
};
|
|
50298
51125
|
ModelTransientFailureError = class extends Error {
|
|
50299
51126
|
constructor(message4) {
|
|
@@ -50498,8 +51325,8 @@ async function postReviewComment(target, body) {
|
|
|
50498
51325
|
const clipped = body.length > MAX_COMMENT_CHARS ? `${body.slice(0, MAX_COMMENT_CHARS)}
|
|
50499
51326
|
|
|
50500
51327
|
_(review truncated to fit GitHub's comment size limit)_` : body;
|
|
50501
|
-
const
|
|
50502
|
-
if (target.commitId)
|
|
51328
|
+
const payload2 = { event: "COMMENT", body: clipped };
|
|
51329
|
+
if (target.commitId) payload2.commit_id = target.commitId;
|
|
50503
51330
|
const res = await fetch(`https://api.github.com/repos/${target.repo}/pulls/${target.number}/reviews`, {
|
|
50504
51331
|
method: "POST",
|
|
50505
51332
|
headers: {
|
|
@@ -50508,7 +51335,7 @@ _(review truncated to fit GitHub's comment size limit)_` : body;
|
|
|
50508
51335
|
"content-type": "application/json",
|
|
50509
51336
|
"user-agent": "switchboard"
|
|
50510
51337
|
},
|
|
50511
|
-
body: JSON.stringify(
|
|
51338
|
+
body: JSON.stringify(payload2),
|
|
50512
51339
|
signal: AbortSignal.timeout(15e3)
|
|
50513
51340
|
});
|
|
50514
51341
|
if (!res.ok) {
|
|
@@ -50828,8 +51655,8 @@ async function runCodingPrPostStep(input) {
|
|
|
50828
51655
|
}
|
|
50829
51656
|
return void 0;
|
|
50830
51657
|
}
|
|
50831
|
-
const
|
|
50832
|
-
const base = prDescription ? await resolveBaseRefLazy(
|
|
51658
|
+
const candidates2 = [target.baseRef, target.bindingRef, target.resolvedRef];
|
|
51659
|
+
const base = prDescription ? await resolveBaseRefLazy(candidates2, repo, input.fetchRepoInfo) : resolveBaseRef(candidates2, void 0);
|
|
50833
51660
|
const pushedBranch = branch2 !== void 0 && branch2 !== base && pushed;
|
|
50834
51661
|
if (pushedBranch && branch2 !== void 0 && headSha !== void 0) {
|
|
50835
51662
|
const clean = observed.uncommittedChanges !== void 0 && observed.unpushedCommits !== void 0 ? observed.uncommittedChanges === 0 && observed.unpushedCommits === 0 : void 0;
|
|
@@ -51933,6 +52760,7 @@ async function runLoop(deps, ctx) {
|
|
|
51933
52760
|
messages,
|
|
51934
52761
|
tools: mergeTools(TOOLSETS[agent.toolset] ?? [], mcpForRun?.tools),
|
|
51935
52762
|
toolContext,
|
|
52763
|
+
...ctx.decisionRecord !== void 0 ? { environment: { [DECISION_RECORD_ENV]: ctx.decisionRecord } } : {},
|
|
51936
52764
|
...session ? { notepad: () => session.readNotepad(), conversation: () => session.readConversation() } : {},
|
|
51937
52765
|
// A failed compaction is a checkpoint signal (harness-pi.md item
|
|
51938
52766
|
// 7): the provider can refuse the process's summary for good, and
|
|
@@ -52275,6 +53103,10 @@ async function runLoop(deps, ctx) {
|
|
|
52275
53103
|
answer,
|
|
52276
53104
|
carried,
|
|
52277
53105
|
hardStopped: false,
|
|
53106
|
+
...coordinator !== void 0 ? {
|
|
53107
|
+
guardTransition: true,
|
|
53108
|
+
fetchPrFacts: deps.fetchPrFacts ?? fetchPullRequestFacts
|
|
53109
|
+
} : { guardTransition: false },
|
|
52278
53110
|
post: deps.postReviewComment ?? postReviewComment,
|
|
52279
53111
|
fetchPrHead: deps.fetchPrHead ?? currentPrHeadSha,
|
|
52280
53112
|
reply: (text) => io.reply(text),
|
|
@@ -52358,6 +53190,7 @@ async function runLoop(deps, ctx) {
|
|
|
52358
53190
|
diagnosis,
|
|
52359
53191
|
root,
|
|
52360
53192
|
ledgerRun,
|
|
53193
|
+
...observedHead !== void 0 ? { headSha: observedHead } : {},
|
|
52361
53194
|
...handoff !== void 0 ? { handoff } : {},
|
|
52362
53195
|
...verdict !== void 0 ? { verdict } : {},
|
|
52363
53196
|
...reviewHead !== void 0 ? { reviewHead } : {},
|
|
@@ -52438,6 +53271,7 @@ var init_runLoop = __esm({
|
|
|
52438
53271
|
"use strict";
|
|
52439
53272
|
init_actor();
|
|
52440
53273
|
init_predicate();
|
|
53274
|
+
init_decisionRecordReservation();
|
|
52441
53275
|
init_profile();
|
|
52442
53276
|
init_provider();
|
|
52443
53277
|
init_toolsets();
|
|
@@ -52521,11 +53355,11 @@ function shipUnitText(requestText, repo) {
|
|
|
52521
53355
|
return t.replace(/\s+/g, " ").trim();
|
|
52522
53356
|
}
|
|
52523
53357
|
function noRepoGuess(input) {
|
|
52524
|
-
const
|
|
52525
|
-
if (
|
|
53358
|
+
const candidates2 = input.repoCandidates ?? [];
|
|
53359
|
+
if (candidates2.length === 0) return void 0;
|
|
52526
53360
|
const typed = REPO_TOKEN.exec(input.requestText)?.[1];
|
|
52527
53361
|
if (typed) {
|
|
52528
|
-
const near = nearMatch(typed,
|
|
53362
|
+
const near = nearMatch(typed, candidates2);
|
|
52529
53363
|
if (near.guess)
|
|
52530
53364
|
return {
|
|
52531
53365
|
line: `agent:ship ${input.requestText.replace(typed, near.guess)}`,
|
|
@@ -52533,8 +53367,8 @@ function noRepoGuess(input) {
|
|
|
52533
53367
|
source: "near"
|
|
52534
53368
|
};
|
|
52535
53369
|
}
|
|
52536
|
-
if (
|
|
52537
|
-
const repo =
|
|
53370
|
+
if (candidates2.length !== 1) return void 0;
|
|
53371
|
+
const repo = candidates2[0];
|
|
52538
53372
|
return {
|
|
52539
53373
|
line: `agent:ship in ${repo}: ${input.requestText}`,
|
|
52540
53374
|
evidence: `\`${repo}\` is the one available repository`,
|
|
@@ -52759,7 +53593,8 @@ async function plan(deps, input) {
|
|
|
52759
53593
|
...entry.adopt !== void 0 ? { adopt: entry.adopt } : {},
|
|
52760
53594
|
...entry.branch !== void 0 ? { entryBranch: entry.branch } : {},
|
|
52761
53595
|
...entry.autoMergeEnabled !== void 0 ? { autoMergeEnabled: entry.autoMergeEnabled } : {},
|
|
52762
|
-
...entry.baseFallback !== void 0 ? { baseFallback: entry.baseFallback } : {}
|
|
53596
|
+
...entry.baseFallback !== void 0 ? { baseFallback: entry.baseFallback } : {},
|
|
53597
|
+
...asksForDecisionRecord(text2) ? { recordTasks: { [graph2.units[0].id]: decisionRecordTaskKey(entry.repo, msg.threadKey, text2.trim()) } } : {}
|
|
52763
53598
|
}
|
|
52764
53599
|
};
|
|
52765
53600
|
}
|
|
@@ -52815,22 +53650,37 @@ async function plan(deps, input) {
|
|
|
52815
53650
|
selected,
|
|
52816
53651
|
identity: identity2,
|
|
52817
53652
|
merge: "runner",
|
|
52818
|
-
...entry.baseFallback !== void 0 ? { baseFallback: entry.baseFallback } : {}
|
|
53653
|
+
...entry.baseFallback !== void 0 ? { baseFallback: entry.baseFallback } : {},
|
|
53654
|
+
recordTasks: Object.fromEntries(
|
|
53655
|
+
graph.units.flatMap((unit) => {
|
|
53656
|
+
const section = parsePlanUnit(text, unit.id)?.section ?? "";
|
|
53657
|
+
return asksForDecisionRecord(section) ? [[unit.id, decisionRecordTaskKey(entry.repo, msg.threadKey, section.trim())]] : [];
|
|
53658
|
+
})
|
|
53659
|
+
)
|
|
52819
53660
|
}
|
|
52820
53661
|
};
|
|
52821
53662
|
}
|
|
52822
|
-
function rowsFor(p, selected, instanceId,
|
|
52823
|
-
|
|
52824
|
-
|
|
52825
|
-
|
|
52826
|
-
|
|
52827
|
-
|
|
52828
|
-
|
|
52829
|
-
|
|
52830
|
-
|
|
52831
|
-
|
|
52832
|
-
|
|
52833
|
-
|
|
53663
|
+
async function rowsFor(deps, p, selected, instanceId, carried) {
|
|
53664
|
+
const reserve = deps.reserveDecisionRecord ?? (() => Promise.reject(new DecisionRecordReservationUnavailableError()));
|
|
53665
|
+
return Promise.all(
|
|
53666
|
+
p.graph.units.filter((u) => selected.includes(u.id)).map(async (u) => {
|
|
53667
|
+
const previous = carried?.get(u.id);
|
|
53668
|
+
const taskKey = p.recordTasks?.[u.id];
|
|
53669
|
+
const record2 = taskKey !== void 0 ? await reserve(p.identity.repo, taskKey, previous?.record) : previous?.record;
|
|
53670
|
+
return {
|
|
53671
|
+
instanceId,
|
|
53672
|
+
unit: u.id,
|
|
53673
|
+
slug: u.slug,
|
|
53674
|
+
title: u.title,
|
|
53675
|
+
branch: p.entryBranch ?? u.branch,
|
|
53676
|
+
dependsOn: u.dependsOn,
|
|
53677
|
+
rounds: [],
|
|
53678
|
+
...p.resume !== void 0 ? { resume: p.resume } : {},
|
|
53679
|
+
...previous?.lastPush !== void 0 ? { lastPush: previous.lastPush } : {},
|
|
53680
|
+
...record2 !== void 0 ? { record: record2 } : {}
|
|
53681
|
+
};
|
|
53682
|
+
})
|
|
53683
|
+
);
|
|
52834
53684
|
}
|
|
52835
53685
|
function planWhere(p, units, mergedBefore, attempt) {
|
|
52836
53686
|
const at = p.path !== void 0 ? ` (\`${p.path}\` at \`${p.base}\`)` : "";
|
|
@@ -52854,6 +53704,15 @@ function planWhere(p, units, mergedBefore, attempt) {
|
|
|
52854
53704
|
return lines;
|
|
52855
53705
|
}
|
|
52856
53706
|
async function handOffToCoordinator(deps, input) {
|
|
53707
|
+
try {
|
|
53708
|
+
return await handOffToCoordinatorUnchecked(deps, input);
|
|
53709
|
+
} catch (error) {
|
|
53710
|
+
if (error instanceof DecisionRecordReservationUnavailableError)
|
|
53711
|
+
return refused5("decision_record_store_unavailable", DECISION_RECORD_STORE_REFUSAL);
|
|
53712
|
+
throw error;
|
|
53713
|
+
}
|
|
53714
|
+
}
|
|
53715
|
+
async function handOffToCoordinatorUnchecked(deps, input) {
|
|
52857
53716
|
const log = deps.log ?? console.log;
|
|
52858
53717
|
const planned = await plan(deps, input);
|
|
52859
53718
|
if (!planned.ok) return refused5(planned.code, planned.reply);
|
|
@@ -52865,7 +53724,7 @@ async function handOffToCoordinator(deps, input) {
|
|
|
52865
53724
|
const firstId = planInstanceId(p.planId);
|
|
52866
53725
|
const first = await deps.instances.get(firstId);
|
|
52867
53726
|
if (first === null) {
|
|
52868
|
-
const units2 = rowsFor(p, p.selected, firstId);
|
|
53727
|
+
const units2 = await rowsFor(deps, p, p.selected, firstId);
|
|
52869
53728
|
const instance2 = {
|
|
52870
53729
|
id: firstId,
|
|
52871
53730
|
...p.identity,
|
|
@@ -52901,11 +53760,16 @@ async function handOffToCoordinator(deps, input) {
|
|
|
52901
53760
|
`\u{1F6AB} A runner for ${where} (\`${latest.id}\`) is in a state the bot does not read as ended (${status3.status}) \u2014 a person decides.`
|
|
52902
53761
|
);
|
|
52903
53762
|
const merged = /* @__PURE__ */ new Set();
|
|
52904
|
-
const
|
|
53763
|
+
const carried = /* @__PURE__ */ new Map();
|
|
52905
53764
|
for (let n2 = 1; n2 <= attempt; n2++)
|
|
52906
53765
|
for (const row2 of await deps.instances.listUnits(planInstanceId(p.planId, n2))) {
|
|
52907
53766
|
if (row2.ending?.kind === "merged") merged.add(row2.unit);
|
|
52908
|
-
|
|
53767
|
+
const prior = carried.get(row2.unit) ?? {};
|
|
53768
|
+
carried.set(row2.unit, {
|
|
53769
|
+
...prior,
|
|
53770
|
+
...row2.lastPush !== void 0 ? { lastPush: row2.lastPush } : {},
|
|
53771
|
+
...row2.record !== void 0 ? { record: row2.record } : {}
|
|
53772
|
+
});
|
|
52909
53773
|
}
|
|
52910
53774
|
const remaining = p.selected.filter((u) => !merged.has(u));
|
|
52911
53775
|
if (remaining.length === 0)
|
|
@@ -52915,7 +53779,7 @@ async function handOffToCoordinator(deps, input) {
|
|
|
52915
53779
|
);
|
|
52916
53780
|
const mergedBefore = p.selected.filter((u) => merged.has(u));
|
|
52917
53781
|
if (status3.kind === "absent") {
|
|
52918
|
-
const units2 = rowsFor(p, remaining, latest.id,
|
|
53782
|
+
const units2 = await rowsFor(deps, p, remaining, latest.id, carried);
|
|
52919
53783
|
const instance2 = {
|
|
52920
53784
|
id: latest.id,
|
|
52921
53785
|
...p.identity,
|
|
@@ -52935,7 +53799,7 @@ async function handOffToCoordinator(deps, input) {
|
|
|
52935
53799
|
);
|
|
52936
53800
|
}
|
|
52937
53801
|
const nextId = planInstanceId(p.planId, attempt + 1);
|
|
52938
|
-
const units = rowsFor(p, remaining, nextId,
|
|
53802
|
+
const units = await rowsFor(deps, p, remaining, nextId, carried);
|
|
52939
53803
|
const instance = {
|
|
52940
53804
|
id: nextId,
|
|
52941
53805
|
...p.identity,
|
|
@@ -53030,6 +53894,7 @@ var init_handOff = __esm({
|
|
|
53030
53894
|
init_budgets();
|
|
53031
53895
|
init_verbosity();
|
|
53032
53896
|
init_contract();
|
|
53897
|
+
init_decisionRecordReservation();
|
|
53033
53898
|
init_preflight();
|
|
53034
53899
|
init_coordinator();
|
|
53035
53900
|
refused5 = (code, reply) => ({
|
|
@@ -53428,6 +54293,7 @@ async function runShipBranch(deps, msg, io, ctx) {
|
|
|
53428
54293
|
{
|
|
53429
54294
|
readFile: (repo, path, ref, opts) => githubCapabilityFor(deps, chatActorOf(deps.config, msg)).api.readFile(repo, path, ref, opts),
|
|
53430
54295
|
instances: deps.coordinatorInstances ?? new NullCoordinatorInstanceStore(),
|
|
54296
|
+
...deps.reserveDecisionRecord !== void 0 ? { reserveDecisionRecord: deps.reserveDecisionRecord } : {},
|
|
53431
54297
|
create: deps.createCoordinatorInstance ?? ((id) => createInstanceViaShim(shim(), id)),
|
|
53432
54298
|
status: deps.fetchCoordinatorInstanceStatus ?? ((id) => fetchInstanceStatusViaShim(shim(), id))
|
|
53433
54299
|
},
|
|
@@ -53960,11 +54826,11 @@ function threadArtifactsBlock(records, opts) {
|
|
|
53960
54826
|
return { text: parts.join("\n\n"), runs: kept.map((k) => k.id), cut, total: rendered.length };
|
|
53961
54827
|
}
|
|
53962
54828
|
async function threadArtifactsFor(input) {
|
|
53963
|
-
const
|
|
53964
|
-
if (
|
|
54829
|
+
const candidates2 = runsSince(input.thread, input.agent).filter(carriesArtifacts);
|
|
54830
|
+
if (candidates2.length === 0) return { notes: [] };
|
|
53965
54831
|
const notes = [];
|
|
53966
54832
|
const reads = await Promise.all(
|
|
53967
|
-
|
|
54833
|
+
candidates2.map(async (view) => {
|
|
53968
54834
|
try {
|
|
53969
54835
|
const res = await input.runs.getRun(view.id, { include: "messages" });
|
|
53970
54836
|
if (res.ok) return res.value;
|
|
@@ -54093,6 +54959,25 @@ __export(dispatcher_exports, {
|
|
|
54093
54959
|
dispatch: () => dispatch,
|
|
54094
54960
|
dispatchClick: () => dispatchClick
|
|
54095
54961
|
});
|
|
54962
|
+
async function priorDecisionRecord(store, threadKey, repo, taskKey) {
|
|
54963
|
+
let before;
|
|
54964
|
+
let beforeId;
|
|
54965
|
+
for (; ; ) {
|
|
54966
|
+
const rows = await store.list({
|
|
54967
|
+
threadKey,
|
|
54968
|
+
agent: "coding",
|
|
54969
|
+
limit: RUN_LIST_MAX_LIMIT,
|
|
54970
|
+
...before !== void 0 ? { before, beforeId } : {}
|
|
54971
|
+
});
|
|
54972
|
+
const match = rows.find((row2) => row2.repo === repo && row2.recordTaskKey === taskKey && row2.record !== void 0);
|
|
54973
|
+
if (match?.record !== void 0) return match.record;
|
|
54974
|
+
if (rows.length < RUN_LIST_MAX_LIMIT) return void 0;
|
|
54975
|
+
const last = rows.at(-1);
|
|
54976
|
+
if (last.finishedAt === before && last.id === beforeId) return void 0;
|
|
54977
|
+
before = last.finishedAt;
|
|
54978
|
+
beforeId = last.id;
|
|
54979
|
+
}
|
|
54980
|
+
}
|
|
54096
54981
|
async function answerUnitOwnedThread(deps, ctx) {
|
|
54097
54982
|
const { msg, io, owner } = ctx;
|
|
54098
54983
|
const store = deps.coordinatorInstances;
|
|
@@ -54235,6 +55120,8 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
54235
55120
|
});
|
|
54236
55121
|
let setupCard;
|
|
54237
55122
|
let setupShell;
|
|
55123
|
+
let decisionRecord;
|
|
55124
|
+
let decisionRecordTask;
|
|
54238
55125
|
let setupHeartbeat;
|
|
54239
55126
|
const admission = deps.admission ?? defaultAdmission;
|
|
54240
55127
|
const registry = deps.runRegistry ?? defaultRunRegistry;
|
|
@@ -54586,6 +55473,36 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
54586
55473
|
if (repoGate.kind === "refused") return ended;
|
|
54587
55474
|
const clip3 = budgetClipLabel(agent, profile, directives.budget, { coordinator: opts.coordinator !== void 0 });
|
|
54588
55475
|
if (clip3) shell.note("debug", clip3);
|
|
55476
|
+
decisionRecord = opts.contract?.record ?? carriedRow?.meta.record;
|
|
55477
|
+
decisionRecordTask = carriedRow?.meta.recordTaskKey;
|
|
55478
|
+
if (decisionRecord === void 0 && agent.name === "coding" && agentSource === "directive" && repoCtx.repo !== void 0 && asksForDecisionRecord(directives.text)) {
|
|
55479
|
+
decisionRecordTask = decisionRecordTaskKey(
|
|
55480
|
+
repoCtx.repo,
|
|
55481
|
+
msg.threadKey,
|
|
55482
|
+
shipUnitText(directives.text, repoCtx.repo).trim()
|
|
55483
|
+
);
|
|
55484
|
+
const prior = await priorDecisionRecord(deps.runStore, msg.threadKey, repoCtx.repo, decisionRecordTask);
|
|
55485
|
+
const reserve = deps.reserveDecisionRecord ?? (async () => {
|
|
55486
|
+
throw new DecisionRecordReservationUnavailableError();
|
|
55487
|
+
});
|
|
55488
|
+
try {
|
|
55489
|
+
decisionRecord = await reserve(repoCtx.repo, decisionRecordTask, prior);
|
|
55490
|
+
} catch (error) {
|
|
55491
|
+
if (!(error instanceof DecisionRecordReservationUnavailableError)) throw error;
|
|
55492
|
+
await refuse3(
|
|
55493
|
+
refusalOf("decision_record_store_unavailable", DECISION_RECORD_STORE_REFUSAL),
|
|
55494
|
+
() => card.done(
|
|
55495
|
+
shell.close({
|
|
55496
|
+
kind: "not_started",
|
|
55497
|
+
icon: "\u26A0\uFE0F",
|
|
55498
|
+
reason: "durable coordinator store unavailable",
|
|
55499
|
+
...closeLines(clock4(), false)
|
|
55500
|
+
})
|
|
55501
|
+
)
|
|
55502
|
+
);
|
|
55503
|
+
return ended;
|
|
55504
|
+
}
|
|
55505
|
+
}
|
|
54589
55506
|
if (agent.name === "ship") {
|
|
54590
55507
|
setupCard = void 0;
|
|
54591
55508
|
clearInterval(setupHeartbeat);
|
|
@@ -54645,7 +55562,8 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
54645
55562
|
const channelBuilt = session ? void 0 : buildConversation(opts.seed ?? history, requestText, msg.images, msg.documents, references.blocks, msg.userId);
|
|
54646
55563
|
const built = session ? session.messages : channelBuilt.messages;
|
|
54647
55564
|
const seedActors = session ? session.actors : channelBuilt?.actors;
|
|
54648
|
-
const
|
|
55565
|
+
const withRecord = !resume && decisionRecord !== void 0 && agent.name === "coding" ? withContractInFirstUserTurn(built, `record: ${decisionRecord}`) : built;
|
|
55566
|
+
const messages = resume ? resume.plan.messages : contractBlock !== void 0 && agent.name !== "review" ? withContractInFirstUserTurn(withRecord, contractBlock) : withRecord;
|
|
54649
55567
|
const headPreflight = await authorizePrHead({
|
|
54650
55568
|
msg,
|
|
54651
55569
|
io,
|
|
@@ -54686,6 +55604,8 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
54686
55604
|
...opts.restartCarried !== void 0 ? { restartCarried: opts.restartCarried } : {},
|
|
54687
55605
|
...seedTurns ? { seedTurns } : {},
|
|
54688
55606
|
agentSource,
|
|
55607
|
+
...decisionRecord !== void 0 ? { decisionRecord } : {},
|
|
55608
|
+
...decisionRecordTask !== void 0 ? { decisionRecordTask } : {},
|
|
54689
55609
|
modelCard,
|
|
54690
55610
|
cardDecisions,
|
|
54691
55611
|
...operatorEvent ? { operator: operatorEvent } : {},
|
|
@@ -54746,6 +55666,8 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
54746
55666
|
parentRunId,
|
|
54747
55667
|
coordinator,
|
|
54748
55668
|
seed,
|
|
55669
|
+
...decisionRecord !== void 0 ? { decisionRecord } : {},
|
|
55670
|
+
...decisionRecordTask !== void 0 ? { decisionRecordTask } : {},
|
|
54749
55671
|
...opts.restartOf !== void 0 ? { restartOf: opts.restartOf } : {}
|
|
54750
55672
|
});
|
|
54751
55673
|
if (reservation) {
|
|
@@ -55068,6 +55990,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
55068
55990
|
isCodingPrRun,
|
|
55069
55991
|
reviewHead,
|
|
55070
55992
|
requestText: directives.text,
|
|
55993
|
+
...decisionRecord !== void 0 ? { decisionRecord } : {},
|
|
55071
55994
|
card,
|
|
55072
55995
|
shell,
|
|
55073
55996
|
doneLines,
|
|
@@ -55409,6 +56332,7 @@ var init_dispatcher = __esm({
|
|
|
55409
56332
|
init_authorize2();
|
|
55410
56333
|
init_messages();
|
|
55411
56334
|
init_staging();
|
|
56335
|
+
init_runRecord();
|
|
55412
56336
|
init_provision();
|
|
55413
56337
|
init_run2();
|
|
55414
56338
|
init_runLoop();
|
|
@@ -55436,7 +56360,9 @@ var init_dispatcher = __esm({
|
|
|
55436
56360
|
init_contract2();
|
|
55437
56361
|
init_runRegistry();
|
|
55438
56362
|
init_runEnding();
|
|
56363
|
+
init_preflight();
|
|
55439
56364
|
init_types5();
|
|
56365
|
+
init_decisionRecordReservation();
|
|
55440
56366
|
activeRuns = 0;
|
|
55441
56367
|
}
|
|
55442
56368
|
});
|
|
@@ -56139,15 +57065,15 @@ function createLedgerWriteThrough(opts) {
|
|
|
56139
57065
|
readNotepad: (key) => ledger.readNotepad(key),
|
|
56140
57066
|
writeNotepad: (key, text) => ledger.writeNotepad(key, gen, text),
|
|
56141
57067
|
async handoff() {
|
|
56142
|
-
const
|
|
56143
|
-
if (
|
|
57068
|
+
const candidates2 = [...live].filter((r) => r.resumable && r.tracked() && !r.handedOff);
|
|
57069
|
+
if (candidates2.length === 0) return { marked: [] };
|
|
56144
57070
|
try {
|
|
56145
57071
|
const { marked } = await ledger.handoff(
|
|
56146
57072
|
gen,
|
|
56147
|
-
|
|
57073
|
+
candidates2.map((r) => r.runId)
|
|
56148
57074
|
);
|
|
56149
57075
|
const markedSet = new Set(marked);
|
|
56150
|
-
for (const r of
|
|
57076
|
+
for (const r of candidates2) if (markedSet.has(r.runId)) r.markHandedOff();
|
|
56151
57077
|
return { marked };
|
|
56152
57078
|
} catch (err2) {
|
|
56153
57079
|
return { marked: [], failed: describe9(err2) };
|
|
@@ -56830,7 +57756,7 @@ function openCodeToolError(outcome, text) {
|
|
|
56830
57756
|
return outcome === "failed" ? { type: "tool.execution", message: text || "The tool call failed" } : { type: "aborted", message: text || "Tool execution interrupted" };
|
|
56831
57757
|
}
|
|
56832
57758
|
function openCodeToolContent(toolUse, resultText, at, outcome = "completed") {
|
|
56833
|
-
const input =
|
|
57759
|
+
const input = isRecord9(toolUse.input) ? toolUse.input : {};
|
|
56834
57760
|
const content = [{ type: "text", text: resultText || "(no output)" }];
|
|
56835
57761
|
return {
|
|
56836
57762
|
type: "tool",
|
|
@@ -56935,11 +57861,11 @@ function openCodeSeedAndRequest(messages) {
|
|
|
56935
57861
|
}
|
|
56936
57862
|
return { seed: messages.slice(), request: "" };
|
|
56937
57863
|
}
|
|
56938
|
-
var
|
|
57864
|
+
var isRecord9, SESSION_TOOL_NAME;
|
|
56939
57865
|
var init_session2 = __esm({
|
|
56940
57866
|
"../../src/core/harness/opencode/session.ts"() {
|
|
56941
57867
|
"use strict";
|
|
56942
|
-
|
|
57868
|
+
isRecord9 = (v) => typeof v === "object" && v !== null;
|
|
56943
57869
|
SESSION_TOOL_NAME = { bash: "shell", find: "glob" };
|
|
56944
57870
|
}
|
|
56945
57871
|
});
|
|
@@ -57391,7 +58317,7 @@ main().then(
|
|
|
57391
58317
|
});
|
|
57392
58318
|
|
|
57393
58319
|
// ../../src/core/harness/opencode/process.ts
|
|
57394
|
-
import { randomBytes as
|
|
58320
|
+
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
57395
58321
|
function openCodeRunPaths(runId3) {
|
|
57396
58322
|
return openCodeRunPathsAt(`${OPENCODE_RUN_ROOT_PREFIX}${runId3}`);
|
|
57397
58323
|
}
|
|
@@ -57574,11 +58500,12 @@ function openCodeLaunchArgs() {
|
|
|
57574
58500
|
return ["serve", "--hostname", "127.0.0.1", "--port", PORT_ARG];
|
|
57575
58501
|
}
|
|
57576
58502
|
function openCodePassword(bearer) {
|
|
57577
|
-
return bearerHashOf(bearer) ??
|
|
58503
|
+
return bearerHashOf(bearer) ?? randomBytes6(24).toString("base64url");
|
|
57578
58504
|
}
|
|
57579
58505
|
function openCodeLaunchEnv(spec, bearer, password) {
|
|
57580
58506
|
const { paths } = spec;
|
|
57581
58507
|
return {
|
|
58508
|
+
...spec.environment,
|
|
57582
58509
|
[RUN_BEARER_ENV]: bearer,
|
|
57583
58510
|
[HARNESS_URL_ENV]: spec.harnessUrl,
|
|
57584
58511
|
SWITCHBOARD_RUN_ID: spec.runId,
|
|
@@ -57797,7 +58724,7 @@ function openCodeToolNameWord(name) {
|
|
|
57797
58724
|
function contentText(content) {
|
|
57798
58725
|
if (typeof content === "string") return content;
|
|
57799
58726
|
if (!Array.isArray(content)) return "";
|
|
57800
|
-
return content.filter((p) =>
|
|
58727
|
+
return content.filter((p) => isRecord10(p) && p.type === "text" && typeof p.text === "string").map((p) => String(p.text)).join("\n");
|
|
57801
58728
|
}
|
|
57802
58729
|
function isBudgetRefusal(error) {
|
|
57803
58730
|
if (error.status !== void 0 && error.status !== 403) return false;
|
|
@@ -57867,8 +58794,8 @@ function toolPartsOf(message4) {
|
|
|
57867
58794
|
const content = message4.content;
|
|
57868
58795
|
const parts = [];
|
|
57869
58796
|
for (const part of Array.isArray(content) ? content : []) {
|
|
57870
|
-
if (!
|
|
57871
|
-
const input =
|
|
58797
|
+
if (!isRecord10(part) || part.type !== "tool") continue;
|
|
58798
|
+
const input = isRecord10(part.state) && isRecord10(part.state.input) ? part.state.input : void 0;
|
|
57872
58799
|
parts.push({ id: str7(part.id), name: str7(part.name), ...input ? { input } : {} });
|
|
57873
58800
|
}
|
|
57874
58801
|
return parts;
|
|
@@ -57889,7 +58816,7 @@ function assistantMessage2(turn) {
|
|
|
57889
58816
|
return {
|
|
57890
58817
|
role: "assistant",
|
|
57891
58818
|
content: turn.content.map(
|
|
57892
|
-
(p) => p.type === "text" ? { type: "text", text: p.text } : p.type === "tool_use" ? { type: "toolCall", id: p.id, name: p.name, arguments:
|
|
58819
|
+
(p) => p.type === "text" ? { type: "text", text: p.text } : p.type === "tool_use" ? { type: "toolCall", id: p.id, name: p.name, arguments: isRecord10(p.input) ? p.input : {} } : {}
|
|
57893
58820
|
)
|
|
57894
58821
|
};
|
|
57895
58822
|
}
|
|
@@ -57918,13 +58845,13 @@ function projectStore(messages, seedLength) {
|
|
|
57918
58845
|
const content = [];
|
|
57919
58846
|
const results = [];
|
|
57920
58847
|
for (const part of Array.isArray(assistant.content) ? assistant.content : []) {
|
|
57921
|
-
if (!
|
|
58848
|
+
if (!isRecord10(part)) continue;
|
|
57922
58849
|
if (part.type === "text" && typeof part.text === "string") content.push({ type: "text", text: part.text });
|
|
57923
58850
|
else if (part.type === "tool") {
|
|
57924
58851
|
const id = str7(part.id);
|
|
57925
58852
|
const name = openCodeToolNameWord(str7(part.name));
|
|
57926
|
-
const state =
|
|
57927
|
-
content.push({ type: "tool_use", id, name, input:
|
|
58853
|
+
const state = isRecord10(part.state) ? part.state : {};
|
|
58854
|
+
content.push({ type: "tool_use", id, name, input: isRecord10(state.input) ? state.input : {} });
|
|
57928
58855
|
if (state.status === "completed" || state.status === "error")
|
|
57929
58856
|
results.push({
|
|
57930
58857
|
type: "tool_result",
|
|
@@ -57944,13 +58871,13 @@ function projectStore(messages, seedLength) {
|
|
|
57944
58871
|
return turns;
|
|
57945
58872
|
}
|
|
57946
58873
|
function errorMessage(error) {
|
|
57947
|
-
return
|
|
58874
|
+
return isRecord10(error) && typeof error.message === "string" ? error.message : "";
|
|
57948
58875
|
}
|
|
57949
58876
|
function statusOf(error) {
|
|
57950
|
-
return
|
|
58877
|
+
return isRecord10(error) && typeof error.status === "number" ? error.status : void 0;
|
|
57951
58878
|
}
|
|
57952
58879
|
function errorTypeOf(error) {
|
|
57953
|
-
return
|
|
58880
|
+
return isRecord10(error) && typeof error.type === "string" ? error.type : void 0;
|
|
57954
58881
|
}
|
|
57955
58882
|
function owedEndNote(how) {
|
|
57956
58883
|
return `the interrupted execution ended (${how}) while the loop read in its own mode \u2014 before the interrupt's answer, or after the write-up's own start; set aside \u2014 the end the loop-end cut owed, not the write-up's settle`;
|
|
@@ -58626,7 +59553,7 @@ async function driveOpenCode(deps, run2, conn, kind = "loop") {
|
|
|
58626
59553
|
const answer = ending ? windDownAnswer(ending, run2.agent.maxMinutes) : unlabelledAnswer(text, void 0);
|
|
58627
59554
|
return { answer, ...ending ? { ending } : {}, remainingMs: remaining, hardStopped: false, ...handOver() };
|
|
58628
59555
|
}
|
|
58629
|
-
var OpenCodeGateBypassedError, OpenCodeReplyFailedError, OpenCodeRequestRefusedError, OpenCodeWriteUnresolvedError, FIRST_EVENT_BOUND_MS, SILENCE_TAIL_BYTES, OpenCodeSilentError, OpenCodeContainerReplacedError, TOOL_NAME_WORD, RESOURCE_PERMISSIONS,
|
|
59556
|
+
var OpenCodeGateBypassedError, OpenCodeReplyFailedError, OpenCodeRequestRefusedError, OpenCodeWriteUnresolvedError, FIRST_EVENT_BOUND_MS, SILENCE_TAIL_BYTES, OpenCodeSilentError, OpenCodeContainerReplacedError, TOOL_NAME_WORD, RESOURCE_PERMISSIONS, isRecord10, str7, TURN_BUDGET_CODE, TURN_BUDGET_REFUSAL, OpenCodeBridge, StepBoundaries, InboxFate;
|
|
58630
59557
|
var init_bridge3 = __esm({
|
|
58631
59558
|
"../../src/core/harness/opencode/bridge.ts"() {
|
|
58632
59559
|
"use strict";
|
|
@@ -58719,7 +59646,7 @@ var init_bridge3 = __esm({
|
|
|
58719
59646
|
};
|
|
58720
59647
|
TOOL_NAME_WORD = { shell: "bash", glob: "find" };
|
|
58721
59648
|
RESOURCE_PERMISSIONS = /* @__PURE__ */ new Set(["external_directory", "doom_loop"]);
|
|
58722
|
-
|
|
59649
|
+
isRecord10 = (v) => typeof v === "object" && v !== null;
|
|
58723
59650
|
str7 = (v) => typeof v === "string" ? v : String(v ?? "");
|
|
58724
59651
|
TURN_BUDGET_CODE = "turn_budget_exhausted";
|
|
58725
59652
|
TURN_BUDGET_REFUSAL = new RegExp(`\\b${TURN_BUDGET_CODE}\\b`);
|
|
@@ -59199,7 +60126,7 @@ var init_bridge3 = __esm({
|
|
|
59199
60126
|
this.noteKindOnce(event.type, `OpenCode emitted ${event.type}, which this run's configuration turns off`);
|
|
59200
60127
|
return out;
|
|
59201
60128
|
}
|
|
59202
|
-
const data =
|
|
60129
|
+
const data = isRecord10(event.data) ? event.data : {};
|
|
59203
60130
|
const earlier2 = this.observing === "earlier";
|
|
59204
60131
|
if (!earlier2 && event.type !== "session.tool.success" && event.type !== "session.tool.failed" && typeof data.assistantMessageID === "string")
|
|
59205
60132
|
this.ownSteps.add(data.assistantMessageID);
|
|
@@ -59311,7 +60238,7 @@ ${data.text}` : data.text;
|
|
|
59311
60238
|
this.openCall(
|
|
59312
60239
|
callId,
|
|
59313
60240
|
this.toolNames.get(callId) ?? "tool",
|
|
59314
|
-
foldInputs(this.takeHeldAsks(callId),
|
|
60241
|
+
foldInputs(this.takeHeldAsks(callId), isRecord10(data.input) ? data.input : void 0)
|
|
59315
60242
|
);
|
|
59316
60243
|
}
|
|
59317
60244
|
/** The call opened on the record — its span, its `tool_call` with the
|
|
@@ -59736,6 +60663,7 @@ async function openOpenCodeRun(deps, run2, settings) {
|
|
|
59736
60663
|
...run2.card ? { card: run2.card } : {},
|
|
59737
60664
|
identity: identity2,
|
|
59738
60665
|
system: run2.system,
|
|
60666
|
+
...run2.environment !== void 0 ? { environment: run2.environment } : {},
|
|
59739
60667
|
relayTools: run2.tools.map((t) => t.name),
|
|
59740
60668
|
...settings.compaction ? { compaction: settings.compaction } : {}
|
|
59741
60669
|
};
|
|
@@ -60463,12 +61391,12 @@ var init_requester = __esm({
|
|
|
60463
61391
|
});
|
|
60464
61392
|
|
|
60465
61393
|
// ../../src/channels/http.ts
|
|
60466
|
-
import { timingSafeEqual as
|
|
61394
|
+
import { timingSafeEqual as timingSafeEqual4 } from "node:crypto";
|
|
60467
61395
|
function safeEqual2(a, b) {
|
|
60468
61396
|
const ab = Buffer.from(a, "utf8");
|
|
60469
61397
|
const bb = Buffer.from(b, "utf8");
|
|
60470
61398
|
if (ab.length !== bb.length) return false;
|
|
60471
|
-
return
|
|
61399
|
+
return timingSafeEqual4(ab, bb);
|
|
60472
61400
|
}
|
|
60473
61401
|
function authenticate(headers, config) {
|
|
60474
61402
|
const header4 = headers.authorization;
|
|
@@ -60493,7 +61421,7 @@ async function toIncomingMessage(identity2, body, personByEmail) {
|
|
|
60493
61421
|
text: body.text
|
|
60494
61422
|
};
|
|
60495
61423
|
}
|
|
60496
|
-
function
|
|
61424
|
+
function parseBody3(raw) {
|
|
60497
61425
|
let parsed;
|
|
60498
61426
|
try {
|
|
60499
61427
|
parsed = JSON.parse(raw);
|
|
@@ -60560,7 +61488,7 @@ function requireDispatch(identity2, grantsFor) {
|
|
|
60560
61488
|
return { status: 403, body: { error: "forbidden", code: "unauthorized" } };
|
|
60561
61489
|
}
|
|
60562
61490
|
async function handleAuthorized(identity2, body, deps, options) {
|
|
60563
|
-
const parsed =
|
|
61491
|
+
const parsed = parseBody3(body);
|
|
60564
61492
|
if ("error" in parsed) {
|
|
60565
61493
|
return { status: 400, body: { error: parsed.error } };
|
|
60566
61494
|
}
|
|
@@ -60605,9 +61533,9 @@ async function readBody(req, maxBytes) {
|
|
|
60605
61533
|
function createIngressHandler(deps, options) {
|
|
60606
61534
|
const maxBytes = options.maxBodyBytes ?? MAX_BODY_BYTES2;
|
|
60607
61535
|
const write = (res, status3, body) => {
|
|
60608
|
-
const
|
|
61536
|
+
const payload2 = JSON.stringify(body);
|
|
60609
61537
|
res.writeHead(status3, { "content-type": "application/json" });
|
|
60610
|
-
res.end(
|
|
61538
|
+
res.end(payload2);
|
|
60611
61539
|
};
|
|
60612
61540
|
return (req, res) => {
|
|
60613
61541
|
void (async () => {
|
|
@@ -60721,6 +61649,16 @@ function refusalResponse(shape, status3, code, message4) {
|
|
|
60721
61649
|
const body = shape === "anthropic-messages" ? { type: "error", error } : { error };
|
|
60722
61650
|
return { status: status3, headers: { "content-type": "application/json" }, body: JSON.stringify(body) };
|
|
60723
61651
|
}
|
|
61652
|
+
function providerFailureResponse(shape, status3, failure2) {
|
|
61653
|
+
const error = authenticateProxyProviderFailure({
|
|
61654
|
+
type: "provider_failure",
|
|
61655
|
+
cause: failure2.cause,
|
|
61656
|
+
message: renderProviderFailure(failure2.cause, providerFailureParks(failure2.cause) ? "parked" : "ended"),
|
|
61657
|
+
...failure2.schemaRejection !== void 0 ? { schemaRejection: failure2.schemaRejection } : {}
|
|
61658
|
+
});
|
|
61659
|
+
const body = shape === "anthropic-messages" ? { type: "error", error } : { error };
|
|
61660
|
+
return { status: status3, headers: { "content-type": "application/json" }, body: JSON.stringify(body) };
|
|
61661
|
+
}
|
|
60724
61662
|
function header(headers, name) {
|
|
60725
61663
|
const raw = headers[name];
|
|
60726
61664
|
return Array.isArray(raw) ? raw[0] : raw;
|
|
@@ -60903,10 +61841,140 @@ function shapeTools(shape, body, marks) {
|
|
|
60903
61841
|
const shaped = { ...rest, tools: kept };
|
|
60904
61842
|
return { body: shaped, toolChoice: toolChoiceWord(shape, void 0, kept.length) };
|
|
60905
61843
|
}
|
|
61844
|
+
function responsesRejectsPattern(pattern) {
|
|
61845
|
+
return /\(\?(?:[=!]|<[=!])/.test(pattern);
|
|
61846
|
+
}
|
|
61847
|
+
function shapeResponsesSchema(value, tool, degradations) {
|
|
61848
|
+
const schema = record(value);
|
|
61849
|
+
if (!schema) {
|
|
61850
|
+
if (!Array.isArray(value)) return { value, changed: false };
|
|
61851
|
+
let changed2 = false;
|
|
61852
|
+
const items = value.map((item) => {
|
|
61853
|
+
const shaped = shapeResponsesSchema(item, tool, degradations);
|
|
61854
|
+
changed2 ||= shaped.changed;
|
|
61855
|
+
return shaped.value;
|
|
61856
|
+
});
|
|
61857
|
+
return { value: changed2 ? items : value, changed: changed2 };
|
|
61858
|
+
}
|
|
61859
|
+
let changed = false;
|
|
61860
|
+
const out = {};
|
|
61861
|
+
for (const [keyword, item] of Object.entries(schema)) {
|
|
61862
|
+
if (keyword === "pattern" && typeof item === "string" && responsesRejectsPattern(item)) {
|
|
61863
|
+
degradations.push({
|
|
61864
|
+
tool,
|
|
61865
|
+
keyword,
|
|
61866
|
+
why: "the Responses wire does not accept regular-expression lookaround"
|
|
61867
|
+
});
|
|
61868
|
+
changed = true;
|
|
61869
|
+
continue;
|
|
61870
|
+
}
|
|
61871
|
+
if ((keyword === "properties" || keyword === "$defs" || keyword === "definitions") && record(item)) {
|
|
61872
|
+
let mapChanged = false;
|
|
61873
|
+
const mapped = {};
|
|
61874
|
+
for (const [name, child] of Object.entries(record(item))) {
|
|
61875
|
+
const shaped = shapeResponsesSchema(child, tool, degradations);
|
|
61876
|
+
mapChanged ||= shaped.changed;
|
|
61877
|
+
mapped[name] = shaped.value;
|
|
61878
|
+
}
|
|
61879
|
+
out[keyword] = mapChanged ? mapped : item;
|
|
61880
|
+
changed ||= mapChanged;
|
|
61881
|
+
continue;
|
|
61882
|
+
}
|
|
61883
|
+
if (["additionalProperties", "allOf", "anyOf", "if", "items", "not", "oneOf", "then", "else"].includes(keyword) && typeof item === "object" && item !== null) {
|
|
61884
|
+
const shaped = shapeResponsesSchema(item, tool, degradations);
|
|
61885
|
+
out[keyword] = shaped.value;
|
|
61886
|
+
changed ||= shaped.changed;
|
|
61887
|
+
continue;
|
|
61888
|
+
}
|
|
61889
|
+
out[keyword] = item;
|
|
61890
|
+
}
|
|
61891
|
+
return { value: changed ? out : value, changed };
|
|
61892
|
+
}
|
|
61893
|
+
function shapeToolSchemasForWire(shape, body) {
|
|
61894
|
+
if (shape !== "openai-responses" || !Array.isArray(body.tools)) return { body, degradations: [] };
|
|
61895
|
+
const degradations = [];
|
|
61896
|
+
let changed = false;
|
|
61897
|
+
const tools = body.tools.map((item) => {
|
|
61898
|
+
const tool = record(item);
|
|
61899
|
+
if (!tool) return item;
|
|
61900
|
+
const name = typeof tool.name === "string" ? tool.name : "unnamed";
|
|
61901
|
+
const shaped = shapeResponsesSchema(tool.parameters, name, degradations);
|
|
61902
|
+
if (!shaped.changed) return item;
|
|
61903
|
+
changed = true;
|
|
61904
|
+
return { ...tool, parameters: shaped.value };
|
|
61905
|
+
});
|
|
61906
|
+
const unique = degradations.filter(
|
|
61907
|
+
(candidate, index, all) => all.findIndex((other) => other.tool === candidate.tool && other.keyword === candidate.keyword) === index
|
|
61908
|
+
);
|
|
61909
|
+
return { body: changed ? { ...body, tools } : body, degradations: unique };
|
|
61910
|
+
}
|
|
60906
61911
|
function toolNameOf(shape, tool) {
|
|
60907
61912
|
if (tool === void 0) return void 0;
|
|
60908
61913
|
return shape === "openai-chat" ? record(tool.function)?.name : tool.name;
|
|
60909
61914
|
}
|
|
61915
|
+
function toolSchemaOf(shape, tool) {
|
|
61916
|
+
if (shape === "anthropic-messages") return tool.input_schema;
|
|
61917
|
+
if (shape === "openai-chat") return record(tool.function)?.parameters;
|
|
61918
|
+
return tool.parameters;
|
|
61919
|
+
}
|
|
61920
|
+
function schemaKeywords(value, into = /* @__PURE__ */ new Set()) {
|
|
61921
|
+
if (Array.isArray(value)) {
|
|
61922
|
+
for (const item of value) schemaKeywords(item, into);
|
|
61923
|
+
return into;
|
|
61924
|
+
}
|
|
61925
|
+
const schema = record(value);
|
|
61926
|
+
if (!schema) return into;
|
|
61927
|
+
for (const [keyword, item] of Object.entries(schema)) {
|
|
61928
|
+
into.add(keyword);
|
|
61929
|
+
if ((keyword === "properties" || keyword === "$defs" || keyword === "definitions") && record(item)) {
|
|
61930
|
+
for (const child of Object.values(record(item))) schemaKeywords(child, into);
|
|
61931
|
+
} else {
|
|
61932
|
+
schemaKeywords(item, into);
|
|
61933
|
+
}
|
|
61934
|
+
}
|
|
61935
|
+
return into;
|
|
61936
|
+
}
|
|
61937
|
+
function providerErrorProse(body) {
|
|
61938
|
+
const strings2 = (value, into = []) => {
|
|
61939
|
+
if (typeof value === "string") into.push(value);
|
|
61940
|
+
else if (Array.isArray(value)) for (const item of value) strings2(item, into);
|
|
61941
|
+
else if (record(value)) for (const item of Object.values(record(value))) strings2(item, into);
|
|
61942
|
+
return into;
|
|
61943
|
+
};
|
|
61944
|
+
try {
|
|
61945
|
+
return strings2(JSON.parse(body)).join(" ");
|
|
61946
|
+
} catch {
|
|
61947
|
+
return body;
|
|
61948
|
+
}
|
|
61949
|
+
}
|
|
61950
|
+
function quoted(text, word) {
|
|
61951
|
+
return [`'${word}'`, `"${word}"`, `\`${word}\``].some((candidate) => text.includes(candidate));
|
|
61952
|
+
}
|
|
61953
|
+
function providerSchemaRejectionOf2(shape, body, errorBody) {
|
|
61954
|
+
const prose2 = providerErrorProse(errorBody);
|
|
61955
|
+
if (!/(?:invalid|unsupported|refused|rejected)[^.!?]{0,80}(?:json )?schema|(?:json )?schema[^.!?]{0,80}(?:invalid|unsupported|not (?:permitted|supported))/i.test(
|
|
61956
|
+
prose2
|
|
61957
|
+
))
|
|
61958
|
+
return void 0;
|
|
61959
|
+
const candidates2 = (Array.isArray(body.tools) ? body.tools : []).map((item) => record(item)).filter((item) => item !== void 0).map((tool) => ({ name: toolNameOf(shape, tool), schema: toolSchemaOf(shape, tool) })).filter(
|
|
61960
|
+
(tool) => typeof tool.name === "string" && quoted(prose2, tool.name)
|
|
61961
|
+
);
|
|
61962
|
+
if (candidates2.length !== 1) return void 0;
|
|
61963
|
+
const [candidate] = candidates2;
|
|
61964
|
+
const keywords = [...schemaKeywords(candidate.schema)].filter((keyword) => quoted(prose2, keyword));
|
|
61965
|
+
if (keywords.length !== 1) return void 0;
|
|
61966
|
+
return { tool: candidate.name, keyword: keywords[0] };
|
|
61967
|
+
}
|
|
61968
|
+
function withSchemaRejection(failure2, schemaRejection) {
|
|
61969
|
+
return new ProviderFailure(failure2.cause, {
|
|
61970
|
+
...failure2.status !== void 0 ? { status: failure2.status } : {},
|
|
61971
|
+
...failure2.provider !== void 0 ? { provider: failure2.provider } : {},
|
|
61972
|
+
...failure2.model !== void 0 ? { model: failure2.model } : {},
|
|
61973
|
+
...failure2.operatorUrl !== void 0 ? { operatorUrl: failure2.operatorUrl } : {},
|
|
61974
|
+
...failure2.keyVariable !== void 0 ? { keyVariable: failure2.keyVariable } : {},
|
|
61975
|
+
schemaRejection
|
|
61976
|
+
});
|
|
61977
|
+
}
|
|
60910
61978
|
function toolsOffered(shape, body) {
|
|
60911
61979
|
const table = Array.isArray(body.tools) ? body.tools : [];
|
|
60912
61980
|
const names = [];
|
|
@@ -61051,8 +62119,15 @@ async function handleAdmitted(door, req, deps) {
|
|
|
61051
62119
|
req.headers
|
|
61052
62120
|
);
|
|
61053
62121
|
if (!upstream.ok) {
|
|
61054
|
-
|
|
61055
|
-
|
|
62122
|
+
const provider = deps.providers()[grant2.providerName];
|
|
62123
|
+
const keyVariable = provider?.apiKeyEnv ?? (shape === "anthropic-messages" ? ANTHROPIC_API_KEY_ENV : void 0);
|
|
62124
|
+
const failure2 = new ProviderFailure(upstream.code === "provider_key_missing" ? "key-absent" : "permanent", {
|
|
62125
|
+
provider: grant2.providerName,
|
|
62126
|
+
model: grant2.model,
|
|
62127
|
+
...upstream.code === "provider_key_missing" && keyVariable !== void 0 ? { keyVariable } : {}
|
|
62128
|
+
});
|
|
62129
|
+
log(`[model-proxy] 503 ${upstream.code} run=${grant2.runId} \u2014 ${failure2.message}`);
|
|
62130
|
+
return providerFailureResponse(shape, 503, failure2);
|
|
61056
62131
|
}
|
|
61057
62132
|
const turn = deps.bearers.consumeTurn(grant2.runId);
|
|
61058
62133
|
if (!turn.ok && turn.reason === "ended") {
|
|
@@ -61076,7 +62151,21 @@ async function handleAdmitted(door, req, deps) {
|
|
|
61076
62151
|
);
|
|
61077
62152
|
}
|
|
61078
62153
|
const shaped = shapeTools(shape, body, deps.bearers.marksOf(grant2.runId));
|
|
61079
|
-
const
|
|
62154
|
+
const schemaShaped = shapeToolSchemasForWire(shape, shaped.body);
|
|
62155
|
+
for (const degradation of schemaShaped.degradations) {
|
|
62156
|
+
grant2.publish({
|
|
62157
|
+
type: "run_note",
|
|
62158
|
+
kind: "control_degraded",
|
|
62159
|
+
control: "tool_schema",
|
|
62160
|
+
asked: `${degradation.tool}.${degradation.keyword}`,
|
|
62161
|
+
applied: "removed",
|
|
62162
|
+
vouched: true,
|
|
62163
|
+
why: degradation.why,
|
|
62164
|
+
summary: `tool "${degradation.tool}" schema keyword "${degradation.keyword}" removed for ${shape}: ${degradation.why}`,
|
|
62165
|
+
at: deps.clock()
|
|
62166
|
+
});
|
|
62167
|
+
}
|
|
62168
|
+
const payload2 = JSON.stringify(pinRequest(shape, schemaShaped.body, grant2));
|
|
61080
62169
|
const offered = { ...toolsOffered(shape, body), toolChoice: shaped.toolChoice };
|
|
61081
62170
|
const startedAt = deps.clock();
|
|
61082
62171
|
const span = grant2.span.start("model.turn", {
|
|
@@ -61098,47 +62187,72 @@ async function handleAdmitted(door, req, deps) {
|
|
|
61098
62187
|
meter2.usage,
|
|
61099
62188
|
deps.prices?.() ?? NO_PRICES
|
|
61100
62189
|
);
|
|
61101
|
-
const outcome = (status3, outBytes) => `[model-proxy] run=${grant2.runId} turn=${turn.turn}/${grant2.maxTurns} ${shape} \u2192 ${status3} in=${Buffer.byteLength(
|
|
62190
|
+
const outcome = (status3, outBytes) => `[model-proxy] run=${grant2.runId} turn=${turn.turn}/${grant2.maxTurns} ${shape} \u2192 ${status3} in=${Buffer.byteLength(payload2)} out=${outBytes} ${Math.max(0, deps.clock() - startedAt)}ms`;
|
|
61102
62191
|
const call2 = () => (deps.fetch ?? fetch)(upstream.url, {
|
|
61103
62192
|
method: "POST",
|
|
61104
62193
|
headers: upstream.headers,
|
|
61105
|
-
body:
|
|
62194
|
+
body: payload2,
|
|
61106
62195
|
...req.signal ? { signal: req.signal } : {}
|
|
61107
62196
|
});
|
|
61108
|
-
const providerDown = () => {
|
|
61109
|
-
deps.plane?.level(grant2.providerName, "down");
|
|
62197
|
+
const providerDown = (failure2) => {
|
|
62198
|
+
deps.plane?.level(grant2.providerName, "down", failure2.cause);
|
|
61110
62199
|
deps.plane?.park(grant2.runId, grant2.providerName);
|
|
61111
62200
|
};
|
|
61112
62201
|
const aborted = () => req.signal?.aborted === true;
|
|
61113
|
-
const
|
|
61114
|
-
if (answer === void 0)
|
|
61115
|
-
|
|
61116
|
-
|
|
62202
|
+
const failureOf2 = async (answer, thrown2) => {
|
|
62203
|
+
if (answer === void 0)
|
|
62204
|
+
return classifyProviderFailure({ error: thrown2 ?? new Error("fetch failed"), provider: grant2.providerName });
|
|
62205
|
+
const contentType2 = (answer.headers.get("content-type") ?? "").toLowerCase();
|
|
62206
|
+
if (answer.ok && !contentType2.includes("text/html")) return void 0;
|
|
62207
|
+
const failureBody = await answer.clone().text().catch(() => "");
|
|
62208
|
+
const failure2 = classifyProviderFailure({
|
|
62209
|
+
status: answer.status,
|
|
62210
|
+
body: failureBody,
|
|
62211
|
+
provider: grant2.providerName,
|
|
62212
|
+
model: grant2.model
|
|
62213
|
+
});
|
|
62214
|
+
const schemaRejection = answer.status === 400 && failure2.cause === "request-rejected" ? providerSchemaRejectionOf2(shape, schemaShaped.body, failureBody) : void 0;
|
|
62215
|
+
return schemaRejection !== void 0 ? withSchemaRejection(failure2, schemaRejection) : failure2;
|
|
61117
62216
|
};
|
|
61118
62217
|
let res;
|
|
61119
|
-
let
|
|
62218
|
+
let thrown;
|
|
61120
62219
|
try {
|
|
61121
62220
|
res = await call2();
|
|
61122
62221
|
} catch (err2) {
|
|
61123
|
-
|
|
62222
|
+
thrown = err2;
|
|
61124
62223
|
}
|
|
61125
|
-
|
|
61126
|
-
|
|
62224
|
+
let providerFailure = await failureOf2(res, thrown);
|
|
62225
|
+
if (providerFailure !== void 0 && providerFailureParks(providerFailure.cause) && !aborted()) {
|
|
62226
|
+
let retried;
|
|
62227
|
+
let retryThrown;
|
|
62228
|
+
try {
|
|
62229
|
+
retried = await call2();
|
|
62230
|
+
} catch (err2) {
|
|
62231
|
+
retryThrown = err2;
|
|
62232
|
+
}
|
|
61127
62233
|
if (retried !== void 0) res = retried;
|
|
61128
|
-
|
|
61129
|
-
|
|
61130
|
-
if (
|
|
61131
|
-
|
|
62234
|
+
providerFailure = await failureOf2(retried ?? res, retryThrown ?? thrown);
|
|
62235
|
+
}
|
|
62236
|
+
if (providerFailure !== void 0 && providerFailureParks(providerFailure.cause) && !aborted())
|
|
62237
|
+
providerDown(providerFailure);
|
|
62238
|
+
const html = (res?.headers.get("content-type") ?? "").toLowerCase().includes("text/html");
|
|
62239
|
+
if (res === void 0 || html) {
|
|
62240
|
+
const failure2 = providerFailure ?? classifyProviderFailure({ error: thrown, provider: grant2.providerName });
|
|
62241
|
+
span.fail(failure2);
|
|
61132
62242
|
span.end("error");
|
|
61133
62243
|
log(`[model-proxy] run=${grant2.runId} turn=${turn.turn}/${grant2.maxTurns} ${shape} \u2192 upstream unreachable`);
|
|
61134
|
-
return
|
|
62244
|
+
return providerFailureResponse(shape, 502, failure2);
|
|
61135
62245
|
}
|
|
61136
62246
|
const headers = pickResponseHeaders(res.headers);
|
|
61137
62247
|
if (!res.ok) {
|
|
61138
62248
|
const text2 = await res.text().catch(() => "");
|
|
62249
|
+
const failure2 = providerFailure ?? classifyProviderFailure({ status: res.status, body: text2, provider: grant2.providerName, model: grant2.model });
|
|
61139
62250
|
span.end("error", { httpStatus: res.status });
|
|
61140
62251
|
log(outcome(res.status, text2.length));
|
|
61141
|
-
return {
|
|
62252
|
+
return {
|
|
62253
|
+
...providerFailureResponse(shape, res.status, failure2),
|
|
62254
|
+
headers: { ...headers, "content-type": "application/json" }
|
|
62255
|
+
};
|
|
61142
62256
|
}
|
|
61143
62257
|
deps.plane?.level(grant2.providerName, "up");
|
|
61144
62258
|
const contentType = res.headers.get("content-type") ?? "";
|
|
@@ -61161,7 +62275,9 @@ async function handleAdmitted(door, req, deps) {
|
|
|
61161
62275
|
log(outcome(res.status, outBytes));
|
|
61162
62276
|
},
|
|
61163
62277
|
onError: (err2) => {
|
|
61164
|
-
providerDown(
|
|
62278
|
+
providerDown(
|
|
62279
|
+
classifyProviderFailure({ status: 503, error: err2, provider: grant2.providerName, model: grant2.model })
|
|
62280
|
+
);
|
|
61165
62281
|
const result = meter2.result();
|
|
61166
62282
|
span.setAttrs(
|
|
61167
62283
|
turnAttrs(grant2, result, firstAt !== void 0 ? firstAt - startedAt : void 0, offered, priceOf2(result))
|
|
@@ -61200,10 +62316,12 @@ function createModelProxyHandler(deps) {
|
|
|
61200
62316
|
...deps,
|
|
61201
62317
|
plane: {
|
|
61202
62318
|
...deps.plane,
|
|
61203
|
-
level: (provider, side) => {
|
|
61204
|
-
|
|
61205
|
-
lastSide.
|
|
61206
|
-
|
|
62319
|
+
level: (provider, side, cause) => {
|
|
62320
|
+
const report2 = side === "down" ? `${side}:${cause ?? "permanent"}` : side;
|
|
62321
|
+
if (lastSide.get(provider) === report2) return;
|
|
62322
|
+
lastSide.set(provider, report2);
|
|
62323
|
+
if (side === "down") deps.plane?.level(provider, side, cause ?? "permanent");
|
|
62324
|
+
else deps.plane?.level(provider, side);
|
|
61207
62325
|
}
|
|
61208
62326
|
}
|
|
61209
62327
|
} : deps;
|
|
@@ -61267,6 +62385,7 @@ var init_modelProxy = __esm({
|
|
|
61267
62385
|
"../../src/channels/modelProxy.ts"() {
|
|
61268
62386
|
"use strict";
|
|
61269
62387
|
init_budgets();
|
|
62388
|
+
init_providerFailureAuth();
|
|
61270
62389
|
init_usage();
|
|
61271
62390
|
init_modelPricing();
|
|
61272
62391
|
init_provider();
|
|
@@ -61636,13 +62755,13 @@ var init_secretStore = __esm({
|
|
|
61636
62755
|
describe() {
|
|
61637
62756
|
return `state Worker ${this.baseUrl} (ConfigDO secrets)`;
|
|
61638
62757
|
}
|
|
61639
|
-
async post(path,
|
|
62758
|
+
async post(path, payload2) {
|
|
61640
62759
|
let res;
|
|
61641
62760
|
try {
|
|
61642
62761
|
res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
61643
62762
|
method: "POST",
|
|
61644
62763
|
headers: { authorization: `Bearer ${this.opts.token}`, "content-type": "application/json" },
|
|
61645
|
-
body: JSON.stringify(
|
|
62764
|
+
body: JSON.stringify(payload2),
|
|
61646
62765
|
signal: AbortSignal.timeout(MCP_SECRET_WORKER_TIMEOUT_MS)
|
|
61647
62766
|
});
|
|
61648
62767
|
} catch (err2) {
|
|
@@ -61880,7 +62999,7 @@ function configRefusalReason(error) {
|
|
|
61880
62999
|
return raw.replace(/^SWITCHBOARD_CONFIG=state:\/\/[^:]+:\s*/, "").slice(0, 1e3);
|
|
61881
63000
|
}
|
|
61882
63001
|
function createConfigRefusalServer(opts) {
|
|
61883
|
-
const
|
|
63002
|
+
const payload2 = {
|
|
61884
63003
|
ok: false,
|
|
61885
63004
|
config: opts.problem,
|
|
61886
63005
|
inFlight: 0,
|
|
@@ -61890,7 +63009,7 @@ function createConfigRefusalServer(opts) {
|
|
|
61890
63009
|
return createServer2((req, res) => {
|
|
61891
63010
|
if (new URL(req.url ?? "/", "http://switchboard.invalid").pathname === "/healthz") {
|
|
61892
63011
|
res.writeHead(503, { "content-type": "application/json" });
|
|
61893
|
-
res.end(JSON.stringify(
|
|
63012
|
+
res.end(JSON.stringify(payload2));
|
|
61894
63013
|
return;
|
|
61895
63014
|
}
|
|
61896
63015
|
res.writeHead(503, { "content-type": "text/plain" });
|
|
@@ -61989,7 +63108,14 @@ async function decideIntake(input, deps) {
|
|
|
61989
63108
|
} catch (err2) {
|
|
61990
63109
|
console.warn(`[intake] ${input.key}: receipt read failed \u2014 ${messageOf(err2)}; deciding as if none`);
|
|
61991
63110
|
}
|
|
61992
|
-
if (row3)
|
|
63111
|
+
if (row3)
|
|
63112
|
+
return {
|
|
63113
|
+
verdict: row3.verdict,
|
|
63114
|
+
reason: row3.reason,
|
|
63115
|
+
source: row3.source,
|
|
63116
|
+
receipt: "existing",
|
|
63117
|
+
...row3.providerFailure !== void 0 ? { providerFailure: row3.providerFailure } : {}
|
|
63118
|
+
};
|
|
61993
63119
|
}
|
|
61994
63120
|
const decided = input.facts.pendingQuestion === true ? {
|
|
61995
63121
|
verdict: "addressed",
|
|
@@ -62012,7 +63138,13 @@ async function decideIntake(input, deps) {
|
|
|
62012
63138
|
try {
|
|
62013
63139
|
const { inserted, stored } = await deps.ledger.recordIntake(input.key, row2);
|
|
62014
63140
|
if (inserted) return { ...decided, receipt: "inserted" };
|
|
62015
|
-
return {
|
|
63141
|
+
return {
|
|
63142
|
+
verdict: stored.verdict,
|
|
63143
|
+
reason: stored.reason,
|
|
63144
|
+
source: stored.source,
|
|
63145
|
+
receipt: "existing",
|
|
63146
|
+
...stored.providerFailure !== void 0 ? { providerFailure: stored.providerFailure } : {}
|
|
63147
|
+
};
|
|
62016
63148
|
} catch (err2) {
|
|
62017
63149
|
console.warn(`[intake] ${input.key}: receipt write failed \u2014 ${messageOf(err2)}; acting on the verdict anyway`);
|
|
62018
63150
|
return { ...decided, receipt: "failed" };
|
|
@@ -62038,10 +63170,20 @@ async function askModel(input, deps) {
|
|
|
62038
63170
|
} catch (err2) {
|
|
62039
63171
|
const timedOut = err2 instanceof Error && (err2.name === "TimeoutError" || err2.name === "AbortError");
|
|
62040
63172
|
const attempts = attemptsOfThrow(err2);
|
|
63173
|
+
if (timedOut) {
|
|
63174
|
+
return {
|
|
63175
|
+
verdict: "silent",
|
|
63176
|
+
reason: tidyReason("the intake call timed out"),
|
|
63177
|
+
source: "timeout",
|
|
63178
|
+
...attempts ? { attempts } : {}
|
|
63179
|
+
};
|
|
63180
|
+
}
|
|
63181
|
+
const failure2 = providerFailureOf(err2);
|
|
62041
63182
|
return {
|
|
62042
63183
|
verdict: "silent",
|
|
62043
|
-
reason:
|
|
62044
|
-
source:
|
|
63184
|
+
reason: renderProviderFailure(failure2.cause, "ended"),
|
|
63185
|
+
source: "error",
|
|
63186
|
+
providerFailure: failure2.cause,
|
|
62045
63187
|
...attempts ? { attempts } : {}
|
|
62046
63188
|
};
|
|
62047
63189
|
}
|
|
@@ -62132,6 +63274,7 @@ var INTAKE_TOOL_NAME, INTAKE_ANSWERS;
|
|
|
62132
63274
|
var init_intake = __esm({
|
|
62133
63275
|
"../../src/core/intake.ts"() {
|
|
62134
63276
|
"use strict";
|
|
63277
|
+
init_provider();
|
|
62135
63278
|
init_redact();
|
|
62136
63279
|
init_structured();
|
|
62137
63280
|
init_untrusted();
|
|
@@ -62367,23 +63510,23 @@ async function fetchImages(files, maxImages, maxTotalBytes = Infinity) {
|
|
|
62367
63510
|
const skipped = [];
|
|
62368
63511
|
const skippedFiles = [];
|
|
62369
63512
|
let bytes = 0;
|
|
62370
|
-
const
|
|
63513
|
+
const candidates2 = [];
|
|
62371
63514
|
for (const f of files ?? []) {
|
|
62372
63515
|
const label = fileLabel(f);
|
|
62373
63516
|
const url = f.url_private_download ?? f.url_private;
|
|
62374
|
-
if (!url || !f.mimetype || !IMAGE_TYPES2.has(f.mimetype) || (f.size ?? 0) > MAX_IMAGE_BYTES ||
|
|
63517
|
+
if (!url || !f.mimetype || !IMAGE_TYPES2.has(f.mimetype) || (f.size ?? 0) > MAX_IMAGE_BYTES || candidates2.length >= maxImages) {
|
|
62375
63518
|
skipped.push(label);
|
|
62376
63519
|
skippedFiles.push(f);
|
|
62377
63520
|
continue;
|
|
62378
63521
|
}
|
|
62379
|
-
|
|
63522
|
+
candidates2.push({ f, label, url, mediaType: f.mimetype });
|
|
62380
63523
|
}
|
|
62381
63524
|
const downloads = await Promise.all(
|
|
62382
|
-
|
|
63525
|
+
candidates2.map(
|
|
62383
63526
|
({ url, label }) => downloadSlackFile(url, label, (contentType) => contentType.includes("text/html"))
|
|
62384
63527
|
)
|
|
62385
63528
|
);
|
|
62386
|
-
|
|
63529
|
+
candidates2.forEach(({ f, label, mediaType }, i) => {
|
|
62387
63530
|
const buf2 = downloads[i];
|
|
62388
63531
|
if (!buf2 || buf2.byteLength > MAX_IMAGE_BYTES || bytes + buf2.byteLength > maxTotalBytes) {
|
|
62389
63532
|
skipped.push(label);
|
|
@@ -62429,24 +63572,24 @@ async function fetchDocuments(files, maxDocs, maxTotalBytes = Infinity) {
|
|
|
62429
63572
|
const skipped = [];
|
|
62430
63573
|
const skippedFiles = [];
|
|
62431
63574
|
let bytes = 0;
|
|
62432
|
-
const
|
|
63575
|
+
const candidates2 = [];
|
|
62433
63576
|
for (const f of files ?? []) {
|
|
62434
63577
|
const label = fileLabel(f);
|
|
62435
63578
|
const url = f.url_private_download ?? f.url_private;
|
|
62436
63579
|
const kind = classifyDocument(f.mimetype, f.name);
|
|
62437
|
-
if (!url || !kind || (f.size ?? 0) > MAX_DOCUMENT_BYTES ||
|
|
63580
|
+
if (!url || !kind || (f.size ?? 0) > MAX_DOCUMENT_BYTES || candidates2.length >= maxDocs) {
|
|
62438
63581
|
skipped.push(label);
|
|
62439
63582
|
skippedFiles.push(f);
|
|
62440
63583
|
continue;
|
|
62441
63584
|
}
|
|
62442
|
-
|
|
63585
|
+
candidates2.push({ f, label, url, kind });
|
|
62443
63586
|
}
|
|
62444
63587
|
const downloads = await Promise.all(
|
|
62445
|
-
|
|
63588
|
+
candidates2.map(
|
|
62446
63589
|
({ url, label, f }) => downloadSlackFile(url, label, (contentType) => contentType.includes("text/html") && f.mimetype !== "text/html")
|
|
62447
63590
|
)
|
|
62448
63591
|
);
|
|
62449
|
-
|
|
63592
|
+
candidates2.forEach(({ f, label, kind }, i) => {
|
|
62450
63593
|
const buf2 = downloads[i];
|
|
62451
63594
|
if (!buf2 || buf2.byteLength > MAX_DOCUMENT_BYTES || bytes + buf2.byteLength > maxTotalBytes) {
|
|
62452
63595
|
skipped.push(label);
|
|
@@ -63133,6 +64276,7 @@ var init_slackSocketStatus = __esm({
|
|
|
63133
64276
|
});
|
|
63134
64277
|
|
|
63135
64278
|
// ../../src/channels/slack.ts
|
|
64279
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
63136
64280
|
import {
|
|
63137
64281
|
App,
|
|
63138
64282
|
SocketModeReceiver,
|
|
@@ -63210,6 +64354,17 @@ function createSlackApp(deps, intake) {
|
|
|
63210
64354
|
const act = await actOnMissedMessage(m, {
|
|
63211
64355
|
botUserId: id,
|
|
63212
64356
|
...intake ? { intake } : {},
|
|
64357
|
+
reply: async (text) => {
|
|
64358
|
+
await new SlackIO(app.client, {
|
|
64359
|
+
channel: m.channel,
|
|
64360
|
+
user: m.user,
|
|
64361
|
+
text: m.text,
|
|
64362
|
+
ts: m.ts,
|
|
64363
|
+
threadTs: m.threadTs,
|
|
64364
|
+
botUserId: id,
|
|
64365
|
+
trigger: "thread-follow-up"
|
|
64366
|
+
}).reply(text);
|
|
64367
|
+
},
|
|
63213
64368
|
dispatch: (extra) => {
|
|
63214
64369
|
void handle(
|
|
63215
64370
|
deps,
|
|
@@ -63318,6 +64473,59 @@ function catchUpDelayNote(messageTs, nowMs) {
|
|
|
63318
64473
|
const late = mins < 1 ? "under a minute" : `${mins} min`;
|
|
63319
64474
|
return `\u23F1 Picked up ${late} after it was posted: the bot was restarting (a deploy or platform move) and Slack does not queue events while it is down. Handling it now \u2014 no need to re-send.`;
|
|
63320
64475
|
}
|
|
64476
|
+
async function deliverIntakeFailure(opts) {
|
|
64477
|
+
if (opts.reply === void 0 || opts.receipt === "existing" && !opts.allowExisting) return;
|
|
64478
|
+
const postWithoutReceipt = async () => {
|
|
64479
|
+
try {
|
|
64480
|
+
await opts.reply(opts.reason);
|
|
64481
|
+
} catch (err2) {
|
|
64482
|
+
opts.failed(err2);
|
|
64483
|
+
}
|
|
64484
|
+
};
|
|
64485
|
+
if (opts.receipt === "failed" || opts.receipt === "absent") {
|
|
64486
|
+
await postWithoutReceipt();
|
|
64487
|
+
return;
|
|
64488
|
+
}
|
|
64489
|
+
const ledger = opts.ledger;
|
|
64490
|
+
if (ledger?.claimIntakeDelivery === void 0 || ledger.finishIntakeDelivery === void 0) {
|
|
64491
|
+
if (opts.receipt === "existing") return;
|
|
64492
|
+
await postWithoutReceipt();
|
|
64493
|
+
return;
|
|
64494
|
+
}
|
|
64495
|
+
let claimed2;
|
|
64496
|
+
try {
|
|
64497
|
+
claimed2 = await ledger.claimIntakeDelivery(opts.key, opts.poster, opts.claimedAt);
|
|
64498
|
+
} catch (err2) {
|
|
64499
|
+
opts.failed(err2);
|
|
64500
|
+
return;
|
|
64501
|
+
}
|
|
64502
|
+
if (!claimed2) return;
|
|
64503
|
+
const alreadyPosted = opts.botUserId !== void 0 && opts.thread.some((message4) => message4.user === opts.botUserId && message4.text === opts.reason);
|
|
64504
|
+
if (alreadyPosted) {
|
|
64505
|
+
try {
|
|
64506
|
+
await ledger.finishIntakeDelivery(opts.key, opts.poster, true);
|
|
64507
|
+
} catch (err2) {
|
|
64508
|
+
opts.failed(err2);
|
|
64509
|
+
}
|
|
64510
|
+
return;
|
|
64511
|
+
}
|
|
64512
|
+
try {
|
|
64513
|
+
await opts.reply(opts.reason);
|
|
64514
|
+
} catch (err2) {
|
|
64515
|
+
try {
|
|
64516
|
+
await ledger.finishIntakeDelivery(opts.key, opts.poster, false);
|
|
64517
|
+
} catch (finishErr) {
|
|
64518
|
+
opts.failed(finishErr);
|
|
64519
|
+
}
|
|
64520
|
+
opts.failed(err2);
|
|
64521
|
+
return;
|
|
64522
|
+
}
|
|
64523
|
+
try {
|
|
64524
|
+
await ledger.finishIntakeDelivery(opts.key, opts.poster, true);
|
|
64525
|
+
} catch (err2) {
|
|
64526
|
+
opts.failed(err2);
|
|
64527
|
+
}
|
|
64528
|
+
}
|
|
63321
64529
|
async function actOnMissedMessage(m, opts) {
|
|
63322
64530
|
const log = opts.log ?? ((line4) => console.log(line4));
|
|
63323
64531
|
const seen = opts.seen ?? { was: wasHandledHere, mark: markHandledHere };
|
|
@@ -63343,6 +64551,20 @@ async function actOnMissedMessage(m, opts) {
|
|
|
63343
64551
|
if (row2) {
|
|
63344
64552
|
decided = true;
|
|
63345
64553
|
silent = row2.verdict === "silent";
|
|
64554
|
+
if (row2.providerFailure !== void 0)
|
|
64555
|
+
await deliverIntakeFailure({
|
|
64556
|
+
key,
|
|
64557
|
+
receipt: "existing",
|
|
64558
|
+
allowExisting: true,
|
|
64559
|
+
ledger: intake.deps.ledger,
|
|
64560
|
+
claimedAt: intake.deps.now(),
|
|
64561
|
+
poster: `${PLATFORM3}:${opts.botUserId}:${intake.gen}:${randomUUID5()}`,
|
|
64562
|
+
reason: row2.reason,
|
|
64563
|
+
thread: m.thread,
|
|
64564
|
+
botUserId: opts.botUserId,
|
|
64565
|
+
...opts.reply ? { reply: opts.reply } : {},
|
|
64566
|
+
failed: (err2) => log(`[catch-up] ${key}: provider failure could not be rendered \u2014 ${describeError3(err2)}`)
|
|
64567
|
+
});
|
|
63346
64568
|
if (silent) log(`[catch-up] ${key}: silenced by its stored receipt (${row2.source}): ${row2.reason}`);
|
|
63347
64569
|
} else {
|
|
63348
64570
|
const page2 = m.thread;
|
|
@@ -63368,6 +64590,20 @@ async function actOnMissedMessage(m, opts) {
|
|
|
63368
64590
|
log(
|
|
63369
64591
|
`[intake] ${key} ${decision.verdict} (${decision.source}, receipt ${decision.receipt}): ${decision.reason} \u2014 decided at catch-up`
|
|
63370
64592
|
);
|
|
64593
|
+
if (decision.providerFailure !== void 0)
|
|
64594
|
+
await deliverIntakeFailure({
|
|
64595
|
+
key,
|
|
64596
|
+
receipt: decision.receipt,
|
|
64597
|
+
allowExisting: true,
|
|
64598
|
+
ledger: intake.deps.ledger,
|
|
64599
|
+
claimedAt: intake.deps.now(),
|
|
64600
|
+
poster: `${PLATFORM3}:${opts.botUserId}:${intake.gen}:${randomUUID5()}`,
|
|
64601
|
+
reason: decision.reason,
|
|
64602
|
+
thread: m.thread,
|
|
64603
|
+
botUserId: opts.botUserId,
|
|
64604
|
+
...opts.reply ? { reply: opts.reply } : {},
|
|
64605
|
+
failed: (err2) => log(`[catch-up] ${key}: provider failure could not be rendered \u2014 ${describeError3(err2)}`)
|
|
64606
|
+
});
|
|
63371
64607
|
decided = true;
|
|
63372
64608
|
silent = decision.verdict !== "addressed";
|
|
63373
64609
|
}
|
|
@@ -63585,6 +64821,28 @@ async function gateThreadReply(client, ev, span, intake, mode, threadKey) {
|
|
|
63585
64821
|
intake.deps
|
|
63586
64822
|
);
|
|
63587
64823
|
span.setAttrs({ intake: decision.verdict, intakeSource: decision.source, intakeReceipt: decision.receipt });
|
|
64824
|
+
if (decision.providerFailure !== void 0) {
|
|
64825
|
+
const key = `${ev.channel}:${ev.ts}`;
|
|
64826
|
+
await deliverIntakeFailure({
|
|
64827
|
+
key,
|
|
64828
|
+
receipt: decision.receipt,
|
|
64829
|
+
allowExisting: false,
|
|
64830
|
+
ledger: intake.deps.ledger,
|
|
64831
|
+
claimedAt: intake.deps.now(),
|
|
64832
|
+
poster: `${PLATFORM3}:${ev.botUserId ?? "unknown"}:${intake.gen}:${randomUUID5()}`,
|
|
64833
|
+
reason: decision.reason,
|
|
64834
|
+
thread: page2,
|
|
64835
|
+
botUserId: ev.botUserId,
|
|
64836
|
+
reply: (text) => new SlackIO(client, ev).reply(text),
|
|
64837
|
+
failed: (err2) => console.error(
|
|
64838
|
+
`[intake] ${key} provider failure could not be rendered \u2014 ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
64839
|
+
)
|
|
64840
|
+
});
|
|
64841
|
+
console.log(
|
|
64842
|
+
`[intake] ${ev.channel}:${ev.ts} ${decision.verdict} (${decision.source}, receipt ${decision.receipt}): ${decision.reason}`
|
|
64843
|
+
);
|
|
64844
|
+
return { proceed: false };
|
|
64845
|
+
}
|
|
63588
64846
|
if (decision.verdict !== "addressed" || decision.receipt === "existing") {
|
|
63589
64847
|
console.log(
|
|
63590
64848
|
`[intake] ${ev.channel}:${ev.ts} ${decision.verdict} (${decision.source}, receipt ${decision.receipt}): ${decision.reason}`
|
|
@@ -64616,9 +65874,9 @@ function createMcpHandler(deps, options) {
|
|
|
64616
65874
|
res.end();
|
|
64617
65875
|
return;
|
|
64618
65876
|
}
|
|
64619
|
-
const
|
|
65877
|
+
const payload2 = JSON.stringify(body);
|
|
64620
65878
|
res.writeHead(status3, { "content-type": "application/json" });
|
|
64621
|
-
res.end(
|
|
65879
|
+
res.end(payload2);
|
|
64622
65880
|
};
|
|
64623
65881
|
return (req, res) => {
|
|
64624
65882
|
void (async () => {
|
|
@@ -64835,29 +66093,29 @@ async function verifyAccessJwt(token2, config, deps) {
|
|
|
64835
66093
|
if (parts.length !== 3) return null;
|
|
64836
66094
|
const [rawHeader, rawPayload, rawSignature] = parts;
|
|
64837
66095
|
const header4 = decodeJsonSegment(rawHeader);
|
|
64838
|
-
const
|
|
64839
|
-
if (!header4 || !
|
|
66096
|
+
const payload2 = decodeJsonSegment(rawPayload);
|
|
66097
|
+
if (!header4 || !payload2) return null;
|
|
64840
66098
|
if (header4.alg !== "RS256") return null;
|
|
64841
66099
|
if (typeof header4.kid !== "string" || header4.kid === "") return null;
|
|
64842
|
-
const
|
|
64843
|
-
if (!
|
|
66100
|
+
const signature2 = decodeBase64Url(rawSignature);
|
|
66101
|
+
if (!signature2) return null;
|
|
64844
66102
|
const jwk = await resolveKey(header4.kid, config, deps);
|
|
64845
66103
|
if (!jwk) return null;
|
|
64846
66104
|
let signatureOk;
|
|
64847
66105
|
try {
|
|
64848
66106
|
const key = createPublicKey({ format: "jwk", key: jwk });
|
|
64849
|
-
signatureOk = cryptoVerify("RSA-SHA256", Buffer.from(`${rawHeader}.${rawPayload}`), key,
|
|
66107
|
+
signatureOk = cryptoVerify("RSA-SHA256", Buffer.from(`${rawHeader}.${rawPayload}`), key, signature2);
|
|
64850
66108
|
} catch {
|
|
64851
66109
|
return null;
|
|
64852
66110
|
}
|
|
64853
66111
|
if (!signatureOk) return null;
|
|
64854
|
-
if (!claimsValid(
|
|
64855
|
-
if (typeof
|
|
64856
|
-
return { sub: "", commonName:
|
|
66112
|
+
if (!claimsValid(payload2, config, deps.now())) return null;
|
|
66113
|
+
if (typeof payload2.sub !== "string" || payload2.sub === "") {
|
|
66114
|
+
return { sub: "", commonName: payload2.common_name };
|
|
64857
66115
|
}
|
|
64858
66116
|
return {
|
|
64859
|
-
sub:
|
|
64860
|
-
email: typeof
|
|
66117
|
+
sub: payload2.sub,
|
|
66118
|
+
email: typeof payload2.email === "string" ? payload2.email : void 0
|
|
64861
66119
|
};
|
|
64862
66120
|
}
|
|
64863
66121
|
function normalizeTeamDomain(raw) {
|
|
@@ -66524,7 +67782,7 @@ var init_residentsView = __esm({
|
|
|
66524
67782
|
});
|
|
66525
67783
|
|
|
66526
67784
|
// ../../src/channels/web.ts
|
|
66527
|
-
import { randomBytes as
|
|
67785
|
+
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
66528
67786
|
function parseThreadsRoute(pathname) {
|
|
66529
67787
|
if (pathname === "/threads" || pathname === "/threads/") return { kind: "new" };
|
|
66530
67788
|
const m = /^\/threads\/([^/]+)(\/send)?\/?$/.exec(pathname);
|
|
@@ -66539,7 +67797,7 @@ function parseThreadsRoute(pathname) {
|
|
|
66539
67797
|
return m[2] ? { kind: "send", id } : { kind: "thread", id };
|
|
66540
67798
|
}
|
|
66541
67799
|
function mintConversationId() {
|
|
66542
|
-
return
|
|
67800
|
+
return randomBytes7(CONVERSATION_ID_BYTES).toString("hex");
|
|
66543
67801
|
}
|
|
66544
67802
|
function threadKeyFor(sub, id) {
|
|
66545
67803
|
return id.includes(":") ? id : `${PLATFORM5}:${sub}:${id}`;
|
|
@@ -67911,7 +69169,7 @@ var init_installationSettings = __esm({
|
|
|
67911
69169
|
});
|
|
67912
69170
|
|
|
67913
69171
|
// ../../src/channels/dashboardAuth.ts
|
|
67914
|
-
import { createHash as createHash5, timingSafeEqual as
|
|
69172
|
+
import { createHash as createHash5, timingSafeEqual as timingSafeEqual5 } from "node:crypto";
|
|
67915
69173
|
function header3(headers, name) {
|
|
67916
69174
|
const raw = headers[name];
|
|
67917
69175
|
return Array.isArray(raw) ? raw[0] : raw;
|
|
@@ -67931,7 +69189,7 @@ function accessVerifier(config, deps) {
|
|
|
67931
69189
|
function secretsEqual(a, b) {
|
|
67932
69190
|
const ha = createHash5("sha256").update(a).digest();
|
|
67933
69191
|
const hb = createHash5("sha256").update(b).digest();
|
|
67934
|
-
return
|
|
69192
|
+
return timingSafeEqual5(ha, hb);
|
|
67935
69193
|
}
|
|
67936
69194
|
function tokenVerifier(opts) {
|
|
67937
69195
|
return {
|
|
@@ -68311,41 +69569,41 @@ function readBuildInfo(path, read = (p) => readFileSync19(p, "utf8")) {
|
|
|
68311
69569
|
}
|
|
68312
69570
|
}
|
|
68313
69571
|
function healthPayload(state) {
|
|
68314
|
-
const
|
|
69572
|
+
const payload2 = {
|
|
68315
69573
|
ok: true,
|
|
68316
69574
|
inFlight: state.inFlight,
|
|
68317
69575
|
draining: state.draining,
|
|
68318
69576
|
drainDeadlineMs: DRAIN_DEADLINE_MS
|
|
68319
69577
|
};
|
|
68320
69578
|
if (state.draining && state.drainStartedAt !== void 0) {
|
|
68321
|
-
|
|
69579
|
+
payload2.drainStartedAt = new Date(state.drainStartedAt).toISOString();
|
|
68322
69580
|
}
|
|
68323
69581
|
if (state.draining && state.held && state.held.length > 0) {
|
|
68324
|
-
|
|
69582
|
+
payload2.held = state.held.map((r) => ({ id: r.id, why: r.why }));
|
|
68325
69583
|
}
|
|
68326
69584
|
if (state.catchUp) {
|
|
68327
69585
|
const catchUp = {};
|
|
68328
69586
|
for (const [k, v] of Object.entries(state.catchUp)) if (v !== void 0) catchUp[k] = v;
|
|
68329
|
-
|
|
69587
|
+
payload2.catchUp = catchUp;
|
|
68330
69588
|
}
|
|
68331
69589
|
if (state.slack) {
|
|
68332
|
-
|
|
69590
|
+
payload2.slack = {
|
|
68333
69591
|
connected: state.slack.connected,
|
|
68334
69592
|
...state.slack.since !== void 0 ? { since: state.slack.since } : {},
|
|
68335
69593
|
...state.slack.connects !== void 0 ? { connects: state.slack.connects } : {}
|
|
68336
69594
|
};
|
|
68337
69595
|
}
|
|
68338
69596
|
if (state.build)
|
|
68339
|
-
|
|
69597
|
+
payload2.build = {
|
|
68340
69598
|
commit: state.build.commit,
|
|
68341
69599
|
...state.build.builtAt !== void 0 ? { builtAt: state.build.builtAt } : {}
|
|
68342
69600
|
};
|
|
68343
|
-
if (state.generation !== void 0)
|
|
68344
|
-
if (state.startedAt !== void 0)
|
|
68345
|
-
if (state.httpListeningAt !== void 0)
|
|
68346
|
-
if (state.process)
|
|
68347
|
-
if (state.artifacts)
|
|
68348
|
-
return
|
|
69601
|
+
if (state.generation !== void 0) payload2.generation = state.generation;
|
|
69602
|
+
if (state.startedAt !== void 0) payload2.startedAt = new Date(state.startedAt).toISOString();
|
|
69603
|
+
if (state.httpListeningAt !== void 0) payload2.httpListeningAt = new Date(state.httpListeningAt).toISOString();
|
|
69604
|
+
if (state.process) payload2.process = { ...state.process };
|
|
69605
|
+
if (state.artifacts) payload2.artifacts = { bucket: state.artifacts.bucket };
|
|
69606
|
+
return payload2;
|
|
68349
69607
|
}
|
|
68350
69608
|
var UNKNOWN_BUILD;
|
|
68351
69609
|
var init_health = __esm({
|
|
@@ -69434,13 +70692,14 @@ async function contractFor(instance, unit, readers) {
|
|
|
69434
70692
|
break;
|
|
69435
70693
|
}
|
|
69436
70694
|
}
|
|
69437
|
-
|
|
70695
|
+
const contract = contractFromPlan({
|
|
69438
70696
|
...source2,
|
|
69439
70697
|
readSpec: (spec) => specs.get(spec),
|
|
69440
70698
|
...agentRules ? { agentRules } : {},
|
|
69441
70699
|
rebase,
|
|
69442
70700
|
...issue ? { issue } : {}
|
|
69443
70701
|
});
|
|
70702
|
+
return unit.record !== void 0 ? { ...contract, record: unit.record } : contract;
|
|
69444
70703
|
}
|
|
69445
70704
|
async function continuationPreface(cont, unit, readers) {
|
|
69446
70705
|
const previous = cont.previousRunId !== void 0 ? await readers.readRunFacts(cont.previousRunId) : void 0;
|
|
@@ -69486,9 +70745,12 @@ async function composeChild(brief, instance, unit, readers) {
|
|
|
69486
70745
|
case "contract": {
|
|
69487
70746
|
const contract = await contractFor(instance, unit, readers);
|
|
69488
70747
|
const task = isGenerated(instance) ? contract.unit.section.split("\n").slice(1).join("\n").trim() : `Implement unit ${contract.unit.id} \u2014 ${contract.unit.title} \u2014 of ${instance.plan?.path ?? "the plan"}: the contract below is the unit. Do its first instruction first, then add every test scenario it lists, update every spec row it names and weaken no guard.`;
|
|
69489
|
-
const
|
|
70748
|
+
const work = unit.record !== void 0 ? `record: ${unit.record}
|
|
69490
70749
|
|
|
69491
70750
|
${task}` : task;
|
|
70751
|
+
const prompt = brief.continue !== void 0 ? `${await continuationPreface(brief.continue, unit, readers)}
|
|
70752
|
+
|
|
70753
|
+
${work}` : work;
|
|
69492
70754
|
return { preset: "coding", prompt, ref: unit.branch, contract };
|
|
69493
70755
|
}
|
|
69494
70756
|
case "review": {
|
|
@@ -69834,6 +71096,7 @@ function watched(io, on) {
|
|
|
69834
71096
|
if (io.attachFile) out.attachFile = (file) => io.attachFile(file);
|
|
69835
71097
|
if (io.uploadTicket) out.uploadTicket = (file) => io.uploadTicket(file);
|
|
69836
71098
|
if (io.runFinished) out.runFinished = (receipt) => io.runFinished(receipt);
|
|
71099
|
+
if (io.requestFailed) out.requestFailed = () => io.requestFailed();
|
|
69837
71100
|
if (io.openThread) out.openThread = (lead) => io.openThread(lead);
|
|
69838
71101
|
return out;
|
|
69839
71102
|
}
|
|
@@ -70014,12 +71277,18 @@ function coordinatorRunView(view, parentInstanceId, finalReply) {
|
|
|
70014
71277
|
parentInstanceId,
|
|
70015
71278
|
...view.idempotencyKey !== void 0 ? { idempotencyKey: view.idempotencyKey } : {},
|
|
70016
71279
|
...view.ownerGen !== void 0 ? { ownerGen: view.ownerGen } : {},
|
|
70017
|
-
...finalReply !== void 0 ? { finalReply } : {}
|
|
71280
|
+
...finalReply !== void 0 ? { finalReply } : {},
|
|
71281
|
+
...view.headSha !== void 0 ? { headSha: view.headSha } : {}
|
|
70018
71282
|
};
|
|
70019
71283
|
}
|
|
70020
71284
|
function prOpenedOf(events) {
|
|
70021
71285
|
const last = [...events ?? []].reverse().find((e) => e.type === "pr_opened");
|
|
70022
|
-
return last && last.type === "pr_opened" ? {
|
|
71286
|
+
return last && last.type === "pr_opened" ? {
|
|
71287
|
+
number: last.number,
|
|
71288
|
+
url: last.url,
|
|
71289
|
+
created: last.created,
|
|
71290
|
+
...last.head !== void 0 ? { head: last.head } : {}
|
|
71291
|
+
} : void 0;
|
|
70023
71292
|
}
|
|
70024
71293
|
async function reviewPostedAt(deps, pr, verdict, head) {
|
|
70025
71294
|
const [reviews, self] = await Promise.all([
|
|
@@ -70065,25 +71334,25 @@ async function postedHumanGateAnswer(deps, pr, requester, addressSeverity) {
|
|
|
70065
71334
|
if (own === void 0) return void 0;
|
|
70066
71335
|
const marker = /<!-- switchboard:verdict (\{[^\n]*\}) -->/.exec(own.body);
|
|
70067
71336
|
if (marker === null) return void 0;
|
|
70068
|
-
let
|
|
71337
|
+
let payload2;
|
|
70069
71338
|
try {
|
|
70070
|
-
|
|
71339
|
+
payload2 = JSON.parse(marker[1]);
|
|
70071
71340
|
} catch {
|
|
70072
71341
|
return void 0;
|
|
70073
71342
|
}
|
|
70074
|
-
if (typeof
|
|
70075
|
-
const row2 =
|
|
71343
|
+
if (typeof payload2 !== "object" || payload2 === null) return void 0;
|
|
71344
|
+
const row2 = payload2;
|
|
70076
71345
|
if (row2.verdict !== "approve" && row2.verdict !== "request_changes") return void 0;
|
|
70077
71346
|
if (!Array.isArray(row2.findings)) return void 0;
|
|
70078
71347
|
const postedFindings = row2.findings.map((finding) => legacyPostedFinding(finding, own.body));
|
|
70079
71348
|
if (!postedFindings.every((finding) => finding !== void 0)) return void 0;
|
|
70080
71349
|
const findings = row2.verdict === "approve" ? findingsAtOrAbove(postedFindings, addressSeverity) : postedFindings;
|
|
70081
71350
|
if (findings.length === 0 || !findings.every((finding) => finding.humanGated === true)) return void 0;
|
|
70082
|
-
const
|
|
71351
|
+
const candidates2 = comments.filter(
|
|
70083
71352
|
(comment) => comment.author.type === "User" && comment.body.trim() !== "" && Number.isFinite(Date.parse(comment.createdAt)) && Date.parse(comment.createdAt) >= githubSecondStart(Date.parse(own.submittedAt))
|
|
70084
71353
|
).sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt));
|
|
70085
71354
|
let answer;
|
|
70086
|
-
for (const candidate of
|
|
71355
|
+
for (const candidate of candidates2) {
|
|
70087
71356
|
const authorized = await deps.commenterAuthorized(requester, candidate.author).catch(() => false);
|
|
70088
71357
|
if (authorized) {
|
|
70089
71358
|
answer = candidate;
|
|
@@ -70117,6 +71386,44 @@ function reviewPostedByRecord(record2, pr) {
|
|
|
70117
71386
|
const same = post.target.repo === pr.repo && post.target.number === pr.number && sameCommit(post.head.toLowerCase(), record2.reviewHead) && post.verdict === record2.verdict.verdict;
|
|
70118
71387
|
return same ? { reviewPosted: true } : void 0;
|
|
70119
71388
|
}
|
|
71389
|
+
function headBranchStateUnknown(facts2) {
|
|
71390
|
+
return facts2.state === "open" && facts2.headBranchExists === void 0;
|
|
71391
|
+
}
|
|
71392
|
+
function headBranchStateError(repo, number) {
|
|
71393
|
+
return `could not verify whether ${repo}#${number}'s head branch exists`;
|
|
71394
|
+
}
|
|
71395
|
+
function pullRequestState(number, fallbackUrl, facts2) {
|
|
71396
|
+
if (headBranchStateUnknown(facts2)) return void 0;
|
|
71397
|
+
const url = facts2.htmlUrl ?? fallbackUrl;
|
|
71398
|
+
if (facts2.mergedAt !== void 0 && facts2.mergeCommitSha !== void 0)
|
|
71399
|
+
return {
|
|
71400
|
+
state: "merged",
|
|
71401
|
+
prNumber: number,
|
|
71402
|
+
url,
|
|
71403
|
+
sha: facts2.mergeCommitSha,
|
|
71404
|
+
mergedAt: facts2.mergedAt,
|
|
71405
|
+
...facts2.mergedBy !== void 0 ? { mergedBy: facts2.mergedBy } : {}
|
|
71406
|
+
};
|
|
71407
|
+
if (facts2.state === "closed")
|
|
71408
|
+
return { state: "closed", prNumber: number, url, closedBy: facts2.closedBy ?? "unknown GitHub user" };
|
|
71409
|
+
return {
|
|
71410
|
+
state: "open",
|
|
71411
|
+
prNumber: number,
|
|
71412
|
+
url,
|
|
71413
|
+
...facts2.headSha !== void 0 ? { headSha: facts2.headSha } : {},
|
|
71414
|
+
...facts2.headBranchExists !== void 0 ? { headBranchExists: facts2.headBranchExists } : {}
|
|
71415
|
+
};
|
|
71416
|
+
}
|
|
71417
|
+
async function childPullRequestState(deps, instance, unit) {
|
|
71418
|
+
if (instance == null || unit === void 0) return void 0;
|
|
71419
|
+
const row2 = (await deps.instances.listUnits(instance.id)).find((candidate) => candidate.unit === unit);
|
|
71420
|
+
if (row2?.pr === void 0) return void 0;
|
|
71421
|
+
const facts2 = await deps.fetchPrFacts({ repo: instance.repo, number: row2.pr.number });
|
|
71422
|
+
if (facts2 === void 0) throw new Error(`could not read ${instance.repo}#${row2.pr.number}`);
|
|
71423
|
+
const state = pullRequestState(row2.pr.number, row2.pr.url, facts2);
|
|
71424
|
+
if (state === void 0) throw new Error(headBranchStateError(instance.repo, row2.pr.number));
|
|
71425
|
+
return state;
|
|
71426
|
+
}
|
|
70120
71427
|
async function readRecord(body, deps) {
|
|
70121
71428
|
const id = parseInstanceId(body.parentInstanceId);
|
|
70122
71429
|
if (!id.ok) return json3(400, { ok: false, error: id.error });
|
|
@@ -70128,13 +71435,35 @@ async function readRecord(body, deps) {
|
|
|
70128
71435
|
const res = await deps.runs.getRun(body.runId);
|
|
70129
71436
|
if (!res.ok || res.value.parentInstanceId !== id.value) return json3(404, { ok: false, error: "not_found" });
|
|
70130
71437
|
const view = res.value;
|
|
70131
|
-
|
|
71438
|
+
const instanceRow = await deps.instances.get(id.value);
|
|
71439
|
+
let pullRequest;
|
|
71440
|
+
try {
|
|
71441
|
+
pullRequest = await childPullRequestState(deps, instanceRow, typeof body.unit === "string" ? body.unit : void 0);
|
|
71442
|
+
} catch (err2) {
|
|
71443
|
+
return json3(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
|
|
71444
|
+
}
|
|
71445
|
+
if (!view.finished)
|
|
71446
|
+
return json3(200, {
|
|
71447
|
+
ok: true,
|
|
71448
|
+
run: coordinatorRunView(view, id.value, void 0),
|
|
71449
|
+
...pullRequest !== void 0 ? { pullRequest } : {},
|
|
71450
|
+
at
|
|
71451
|
+
});
|
|
70132
71452
|
const full = await deps.runs.getRun(body.runId, { include: "messages" });
|
|
70133
71453
|
const record2 = full.ok ? full.value : view;
|
|
70134
71454
|
const finalReply = finalReplyOf2(record2.events);
|
|
70135
71455
|
const reviewAskedAt = reviewAskedAtOf(record2.events);
|
|
70136
|
-
const
|
|
70137
|
-
const
|
|
71456
|
+
const opened = prOpenedOf(record2.events);
|
|
71457
|
+
const pr = opened !== void 0 ? { number: opened.number, url: opened.url, created: opened.created } : void 0;
|
|
71458
|
+
let coordinatorUnit;
|
|
71459
|
+
if (instanceRow !== null && typeof body.unit === "string") {
|
|
71460
|
+
coordinatorUnit = (await deps.instances.listUnits(instanceRow.id)).find((u) => u.unit === body.unit);
|
|
71461
|
+
const pushedPrRef = opened?.head !== void 0 && record2.pushed?.some((pushed) => pushed.ref === opened.head) ? opened.head : void 0;
|
|
71462
|
+
if (coordinatorUnit !== void 0 && pushedPrRef !== void 0 && coordinatorUnit.branch !== pushedPrRef) {
|
|
71463
|
+
coordinatorUnit = { ...coordinatorUnit, branch: pushedPrRef };
|
|
71464
|
+
await deps.instances.putUnits([coordinatorUnit]);
|
|
71465
|
+
}
|
|
71466
|
+
}
|
|
70138
71467
|
if (view.status === "interrupted") {
|
|
70139
71468
|
const successor = await restartedChildOf(deps, id.value, view).catch(() => void 0);
|
|
70140
71469
|
if (successor !== void 0)
|
|
@@ -70142,6 +71471,7 @@ async function readRecord(body, deps) {
|
|
|
70142
71471
|
ok: true,
|
|
70143
71472
|
...instanceRow?.stop !== void 0 ? { stopped: true } : {},
|
|
70144
71473
|
run: { id: successor, finished: false },
|
|
71474
|
+
...pullRequest !== void 0 ? { pullRequest } : {},
|
|
70145
71475
|
restartedAs: successor,
|
|
70146
71476
|
at
|
|
70147
71477
|
});
|
|
@@ -70150,15 +71480,15 @@ async function readRecord(body, deps) {
|
|
|
70150
71480
|
ok: true,
|
|
70151
71481
|
...instanceRow?.stop !== void 0 ? { stopped: true } : {},
|
|
70152
71482
|
run: { id: view.id, finished: false },
|
|
71483
|
+
...pullRequest !== void 0 ? { pullRequest } : {},
|
|
70153
71484
|
at
|
|
70154
71485
|
});
|
|
70155
71486
|
}
|
|
70156
71487
|
let posted;
|
|
70157
71488
|
if (record2.verdict !== void 0 && record2.reviewHead !== void 0 && typeof body.unit === "string") {
|
|
70158
71489
|
const instance = instanceRow;
|
|
70159
|
-
|
|
70160
|
-
|
|
70161
|
-
const unitPr = { repo: instance.repo, number: row2.pr.number };
|
|
71490
|
+
if (instance && coordinatorUnit?.pr !== void 0) {
|
|
71491
|
+
const unitPr = { repo: instance.repo, number: coordinatorUnit.pr.number };
|
|
70162
71492
|
posted = reviewPostedByRecord(record2, unitPr);
|
|
70163
71493
|
if (posted === void 0) {
|
|
70164
71494
|
const seen = await reviewPostedAtPatiently(deps, unitPr, record2.verdict.verdict, record2.reviewHead);
|
|
@@ -70169,6 +71499,7 @@ async function readRecord(body, deps) {
|
|
|
70169
71499
|
return json3(200, {
|
|
70170
71500
|
ok: true,
|
|
70171
71501
|
...instanceRow?.stop !== void 0 ? { stopped: true } : {},
|
|
71502
|
+
...pullRequest !== void 0 ? { pullRequest } : {},
|
|
70172
71503
|
run: {
|
|
70173
71504
|
...coordinatorRunView(view, id.value, finalReply),
|
|
70174
71505
|
...pr !== void 0 ? { pr } : {},
|
|
@@ -70296,6 +71627,24 @@ async function recoverPushedBranch(deps, instance, row2, branch2, runId3) {
|
|
|
70296
71627
|
throw err2;
|
|
70297
71628
|
}
|
|
70298
71629
|
}
|
|
71630
|
+
async function steerChild(body, deps) {
|
|
71631
|
+
const id = parseInstanceId(body.parentInstanceId);
|
|
71632
|
+
if (!id.ok) return json3(400, { ok: false, error: id.error });
|
|
71633
|
+
if (typeof body.runId !== "string" || !RUN_ID_PATTERN.test(body.runId))
|
|
71634
|
+
return json3(400, { ok: false, error: "runId must be a run id" });
|
|
71635
|
+
if (typeof body.reason !== "string" || !CHILD_SUPERSESSION_REASONS.has(body.reason))
|
|
71636
|
+
return json3(400, { ok: false, error: "reason must name a pull request transition" });
|
|
71637
|
+
const at = (deps.clock ?? systemClock)();
|
|
71638
|
+
const instance = await deps.instances.get(id.value);
|
|
71639
|
+
if (instance === null) return json3(404, { ok: false, error: "unknown_instance", at });
|
|
71640
|
+
const child = await deps.runs.getRun(body.runId);
|
|
71641
|
+
if (!child.ok || child.value.parentInstanceId !== instance.id)
|
|
71642
|
+
return json3(404, { ok: false, error: "not_found", at });
|
|
71643
|
+
const reason2 = body.reason === "merged" ? "The pull request merged while this run was live." : body.reason === "closed" ? "The pull request closed while this run was live." : body.reason === "head_moved" ? "The pull request moved to another head while this review was live." : "The pull request's head branch was deleted while this run was live.";
|
|
71644
|
+
const text = `${reason2} End now without a push or a review post. Record what already happened in the run's final reply.`;
|
|
71645
|
+
const steered = await deps.steerChild?.(body.runId, text, instance) ?? false;
|
|
71646
|
+
return json3(200, { ok: true, outcome: steered ? "steered" : "not_live", at });
|
|
71647
|
+
}
|
|
70299
71648
|
async function prCheck(body, deps) {
|
|
70300
71649
|
const id = parseInstanceId(body.parentInstanceId);
|
|
70301
71650
|
if (!id.ok) return json3(400, { ok: false, error: id.error });
|
|
@@ -70317,6 +71666,42 @@ async function prCheck(body, deps) {
|
|
|
70317
71666
|
await deps.instances.putUnits([{ ...unit.row, pr }]);
|
|
70318
71667
|
};
|
|
70319
71668
|
try {
|
|
71669
|
+
if (follow !== void 0) {
|
|
71670
|
+
const facts2 = await deps.fetchPrFacts({ repo: instance.repo, number: follow });
|
|
71671
|
+
if (facts2 === void 0) throw new Error(`could not read ${instance.repo}#${follow}`);
|
|
71672
|
+
const fallbackUrl = unit.row?.pr?.url ?? `https://github.com/${instance.repo}/pull/${follow}`;
|
|
71673
|
+
const state2 = pullRequestState(follow, fallbackUrl, facts2);
|
|
71674
|
+
if (state2 === void 0) throw new Error(headBranchStateError(instance.repo, follow));
|
|
71675
|
+
await remember({ number: follow, url: String(state2.url) });
|
|
71676
|
+
if (state2.state !== "open") return json3(200, { ok: true, ...state2, at });
|
|
71677
|
+
const prRef = { repo: instance.repo, number: follow };
|
|
71678
|
+
const headSha = facts2.headSha;
|
|
71679
|
+
const approved = entry && headSha !== void 0 ? await reviewPostedAt(deps, prRef, "approve", headSha) : void 0;
|
|
71680
|
+
const humanGate = entry ? await postedHumanGateAnswer(
|
|
71681
|
+
deps,
|
|
71682
|
+
prRef,
|
|
71683
|
+
instance.userId,
|
|
71684
|
+
instance.addressSeverity ?? DEFAULT_ADDRESS_SEVERITY
|
|
71685
|
+
) : void 0;
|
|
71686
|
+
const entryChecks = entry && headSha !== void 0 ? await deps.fetchCommitChecks(instance.repo, headSha).catch(() => void 0) : void 0;
|
|
71687
|
+
const checks = body.checks === true && headSha !== void 0 ? await deps.fetchCommitChecks(instance.repo, headSha).catch(() => void 0) : entryChecks;
|
|
71688
|
+
const fixups = body.checks === true ? await deps.fixupCommitSubjects(prRef).catch(() => void 0) : void 0;
|
|
71689
|
+
const queueBase = facts2.baseRef ?? instance.base;
|
|
71690
|
+
const baseHasMergeQueue = body.checks === true && deps.branchHasMergeQueue !== void 0 && queueBase !== void 0 ? await deps.branchHasMergeQueue(instance.repo, queueBase).catch(() => void 0) : void 0;
|
|
71691
|
+
return json3(200, {
|
|
71692
|
+
ok: true,
|
|
71693
|
+
...state2,
|
|
71694
|
+
...entry && headSha !== void 0 ? { branchHead: headSha } : {},
|
|
71695
|
+
...approved !== void 0 ? { approved } : {},
|
|
71696
|
+
...humanGate !== void 0 ? { humanGate } : {},
|
|
71697
|
+
...facts2.autoMergeEnabled !== void 0 ? { autoMergeEnabled: facts2.autoMergeEnabled } : {},
|
|
71698
|
+
...checks !== void 0 ? { checks } : {},
|
|
71699
|
+
...body.checks === true && facts2.mergeableState !== void 0 ? { mergeableState: facts2.mergeableState } : {},
|
|
71700
|
+
...fixups !== void 0 ? { fixupCommits: fixups } : {},
|
|
71701
|
+
...typeof baseHasMergeQueue === "boolean" ? { baseHasMergeQueue } : {},
|
|
71702
|
+
at
|
|
71703
|
+
});
|
|
71704
|
+
}
|
|
70320
71705
|
const open2 = await deps.findOpenPrByHead(instance.repo, branch2);
|
|
70321
71706
|
if (open2) {
|
|
70322
71707
|
await remember({ number: open2.number, url: open2.htmlUrl });
|
|
@@ -70324,7 +71709,12 @@ async function prCheck(body, deps) {
|
|
|
70324
71709
|
instanceId: instance.id,
|
|
70325
71710
|
unit: unit.row?.unit ?? body.unit
|
|
70326
71711
|
});
|
|
70327
|
-
const
|
|
71712
|
+
const liveFacts = await deps.fetchPrFacts({ repo: instance.repo, number: open2.number });
|
|
71713
|
+
if (liveFacts === void 0) throw new Error(`could not read ${instance.repo}#${open2.number}`);
|
|
71714
|
+
const current = pullRequestState(open2.number, open2.htmlUrl, liveFacts);
|
|
71715
|
+
if (current === void 0) throw new Error(headBranchStateError(instance.repo, open2.number));
|
|
71716
|
+
if (current.state !== "open") return json3(200, { ok: true, ...current, at });
|
|
71717
|
+
const entryFacts = entry ? liveFacts : void 0;
|
|
70328
71718
|
const branchHead = entryFacts?.headSha;
|
|
70329
71719
|
const entryHead = branchHead ?? open2.headSha;
|
|
70330
71720
|
const approved = entry && entryHead !== void 0 ? await reviewPostedAt(deps, { repo: instance.repo, number: open2.number }, "approve", entryHead) : void 0;
|
|
@@ -70337,7 +71727,7 @@ async function prCheck(body, deps) {
|
|
|
70337
71727
|
const entryChecks = entry && entryHead !== void 0 ? await deps.fetchCommitChecks(instance.repo, entryHead).catch(() => void 0) : void 0;
|
|
70338
71728
|
const checks = body.checks === true && open2.headSha !== void 0 ? await deps.fetchCommitChecks(instance.repo, open2.headSha).catch(() => void 0) : entryChecks;
|
|
70339
71729
|
const prRef = { repo: instance.repo, number: open2.number };
|
|
70340
|
-
const facts2 = body.checks === true ?
|
|
71730
|
+
const facts2 = body.checks === true ? liveFacts : void 0;
|
|
70341
71731
|
const fixups = body.checks === true ? await deps.fixupCommitSubjects(prRef).catch(() => void 0) : void 0;
|
|
70342
71732
|
const queueBase = facts2?.baseRef ?? instance.base;
|
|
70343
71733
|
const baseHasMergeQueue = body.checks === true && deps.branchHasMergeQueue !== void 0 && queueBase !== void 0 ? await deps.branchHasMergeQueue(instance.repo, queueBase).catch(() => void 0) : void 0;
|
|
@@ -70346,7 +71736,8 @@ async function prCheck(body, deps) {
|
|
|
70346
71736
|
state: "open",
|
|
70347
71737
|
prNumber: open2.number,
|
|
70348
71738
|
url: open2.htmlUrl,
|
|
70349
|
-
...
|
|
71739
|
+
...liveFacts.headSha !== void 0 ? { headSha: liveFacts.headSha } : {},
|
|
71740
|
+
...liveFacts.headBranchExists !== void 0 ? { headBranchExists: liveFacts.headBranchExists } : {},
|
|
70350
71741
|
...branchHead !== void 0 ? { branchHead } : {},
|
|
70351
71742
|
...approved !== void 0 ? { approved } : {},
|
|
70352
71743
|
...humanGate !== void 0 ? { humanGate } : {},
|
|
@@ -70362,39 +71753,6 @@ async function prCheck(body, deps) {
|
|
|
70362
71753
|
}
|
|
70363
71754
|
const merged = await deps.findMergedPrByHead(instance.repo, branch2);
|
|
70364
71755
|
if (!merged) {
|
|
70365
|
-
if (follow !== void 0 && recover === void 0) {
|
|
70366
|
-
const facts2 = await deps.fetchPrFacts({ repo: instance.repo, number: follow });
|
|
70367
|
-
if (facts2 !== void 0) {
|
|
70368
|
-
const url = facts2.htmlUrl ?? `https://github.com/${instance.repo}/pull/${follow}`;
|
|
70369
|
-
if (facts2.mergedAt !== void 0 && facts2.mergeCommitSha !== void 0) {
|
|
70370
|
-
await remember({ number: follow, url });
|
|
70371
|
-
return json3(200, {
|
|
70372
|
-
ok: true,
|
|
70373
|
-
state: "merged",
|
|
70374
|
-
prNumber: follow,
|
|
70375
|
-
url,
|
|
70376
|
-
sha: facts2.mergeCommitSha,
|
|
70377
|
-
mergedAt: facts2.mergedAt,
|
|
70378
|
-
at
|
|
70379
|
-
});
|
|
70380
|
-
}
|
|
70381
|
-
if (facts2.state === "open") {
|
|
70382
|
-
await remember({ number: follow, url });
|
|
70383
|
-
const checks = body.checks === true && facts2.headSha !== void 0 ? await deps.fetchCommitChecks(instance.repo, facts2.headSha).catch(() => void 0) : void 0;
|
|
70384
|
-
return json3(200, {
|
|
70385
|
-
ok: true,
|
|
70386
|
-
state: "open",
|
|
70387
|
-
prNumber: follow,
|
|
70388
|
-
url,
|
|
70389
|
-
...facts2.headSha !== void 0 ? { headSha: facts2.headSha } : {},
|
|
70390
|
-
...facts2.autoMergeEnabled !== void 0 ? { autoMergeEnabled: facts2.autoMergeEnabled } : {},
|
|
70391
|
-
...checks !== void 0 ? { checks } : {},
|
|
70392
|
-
at
|
|
70393
|
-
});
|
|
70394
|
-
}
|
|
70395
|
-
return json3(200, { ok: true, state: "none", prClosed: true, at });
|
|
70396
|
-
}
|
|
70397
|
-
}
|
|
70398
71756
|
if (recover === void 0) {
|
|
70399
71757
|
const ahead = instance.base === void 0 ? void 0 : await deps.commitsOverBase(instance.repo, instance.base, branch2).catch((err2) => {
|
|
70400
71758
|
(deps.log ?? console.log)(
|
|
@@ -70407,20 +71765,20 @@ async function prCheck(body, deps) {
|
|
|
70407
71765
|
const recovered = await recoverPushedBranch(deps, instance, unit.row, branch2, recover.runId);
|
|
70408
71766
|
if (recovered.kind === "opened") {
|
|
70409
71767
|
await remember({ number: recovered.pr.number, url: recovered.pr.htmlUrl });
|
|
70410
|
-
|
|
71768
|
+
const recoveredFacts = await deps.fetchPrFacts({ repo: instance.repo, number: recovered.pr.number });
|
|
71769
|
+
if (recoveredFacts === void 0) throw new Error(`could not read ${instance.repo}#${recovered.pr.number}`);
|
|
71770
|
+
const recoveredState = pullRequestState(recovered.pr.number, recovered.pr.htmlUrl, recoveredFacts);
|
|
71771
|
+
if (recoveredState === void 0) throw new Error(headBranchStateError(instance.repo, recovered.pr.number));
|
|
71772
|
+
return json3(200, { ok: true, ...recoveredState, at });
|
|
70411
71773
|
}
|
|
70412
71774
|
return json3(200, { ok: true, state: "none", unrecovered: recovered.why, at });
|
|
70413
71775
|
}
|
|
70414
71776
|
await remember({ number: merged.number, url: merged.htmlUrl });
|
|
70415
|
-
|
|
70416
|
-
|
|
70417
|
-
|
|
70418
|
-
|
|
70419
|
-
|
|
70420
|
-
sha: merged.sha,
|
|
70421
|
-
mergedAt: merged.mergedAt,
|
|
70422
|
-
at
|
|
70423
|
-
});
|
|
71777
|
+
const mergedFacts = await deps.fetchPrFacts({ repo: instance.repo, number: merged.number });
|
|
71778
|
+
if (mergedFacts === void 0) throw new Error(`could not read ${instance.repo}#${merged.number}`);
|
|
71779
|
+
const state = pullRequestState(merged.number, merged.htmlUrl, mergedFacts);
|
|
71780
|
+
if (state?.state !== "merged") throw new Error(`${instance.repo}#${merged.number} no longer reads merged`);
|
|
71781
|
+
return json3(200, { ok: true, ...state, at });
|
|
70424
71782
|
} catch (err2) {
|
|
70425
71783
|
return json3(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
|
|
70426
71784
|
}
|
|
@@ -71124,6 +72482,13 @@ async function merge(body, deps, subject2) {
|
|
|
71124
72482
|
}
|
|
71125
72483
|
if (facts2 === void 0)
|
|
71126
72484
|
return json3(502, { ok: false, error: "github_unavailable", message: `${where} could not be read`, at });
|
|
72485
|
+
if (headBranchStateUnknown(facts2))
|
|
72486
|
+
return json3(502, {
|
|
72487
|
+
ok: false,
|
|
72488
|
+
error: "github_unavailable",
|
|
72489
|
+
message: headBranchStateError(instance.repo, pr.number),
|
|
72490
|
+
at
|
|
72491
|
+
});
|
|
71127
72492
|
if (isReleasePullRequest(facts2))
|
|
71128
72493
|
return refused7(`${where} is the release pull request \u2014 always a person's merge, never the runner's`);
|
|
71129
72494
|
if (facts2.state !== "open") {
|
|
@@ -71134,9 +72499,23 @@ async function merge(body, deps, subject2) {
|
|
|
71134
72499
|
by: "other",
|
|
71135
72500
|
sha: facts2.mergeCommitSha,
|
|
71136
72501
|
mergedAt: facts2.mergedAt,
|
|
72502
|
+
...facts2.mergedBy !== void 0 ? { mergedBy: facts2.mergedBy } : {},
|
|
71137
72503
|
at
|
|
71138
72504
|
});
|
|
71139
|
-
|
|
72505
|
+
const pullRequest = pullRequestState(
|
|
72506
|
+
body.prNumber,
|
|
72507
|
+
row2.pr?.url ?? `https://github.com/${instance.repo}/pull/${body.prNumber}`,
|
|
72508
|
+
facts2
|
|
72509
|
+
);
|
|
72510
|
+
return pullRequest === void 0 ? refused7(`${where} is ${facts2.state}`) : json3(200, { ok: true, outcome: "recheck", pullRequest, at });
|
|
72511
|
+
}
|
|
72512
|
+
if (facts2.headBranchExists === false) {
|
|
72513
|
+
const pullRequest = pullRequestState(
|
|
72514
|
+
body.prNumber,
|
|
72515
|
+
row2.pr?.url ?? `https://github.com/${instance.repo}/pull/${body.prNumber}`,
|
|
72516
|
+
facts2
|
|
72517
|
+
);
|
|
72518
|
+
if (pullRequest !== void 0) return json3(200, { ok: true, outcome: "recheck", pullRequest, at });
|
|
71140
72519
|
}
|
|
71141
72520
|
if (body.queued === true) {
|
|
71142
72521
|
const queue = deps.fetchMergeQueueState !== void 0 ? await deps.fetchMergeQueueState(pr).catch(() => void 0) : void 0;
|
|
@@ -71163,10 +72542,14 @@ async function merge(body, deps, subject2) {
|
|
|
71163
72542
|
}
|
|
71164
72543
|
if (facts2.headRef !== row2.branch)
|
|
71165
72544
|
return refused7(`${where} heads \`${facts2.headRef ?? "?"}\`, not the unit's branch \`${row2.branch}\``);
|
|
71166
|
-
if (facts2.headSha === void 0 || !sameCommit(facts2.headSha, headSha))
|
|
71167
|
-
|
|
71168
|
-
|
|
72545
|
+
if (facts2.headSha === void 0 || !sameCommit(facts2.headSha, headSha)) {
|
|
72546
|
+
const pullRequest = pullRequestState(
|
|
72547
|
+
body.prNumber,
|
|
72548
|
+
row2.pr?.url ?? `https://github.com/${instance.repo}/pull/${body.prNumber}`,
|
|
72549
|
+
facts2
|
|
71169
72550
|
);
|
|
72551
|
+
return pullRequest === void 0 ? refused7(`the head of ${where} could not be read`) : json3(200, { ok: true, outcome: "recheck", pullRequest, at });
|
|
72552
|
+
}
|
|
71170
72553
|
if (facts2.mergeableState === "dirty") {
|
|
71171
72554
|
const base = facts2.baseRef ?? "its base";
|
|
71172
72555
|
return json3(200, {
|
|
@@ -71267,6 +72650,22 @@ async function checksStep(body, deps) {
|
|
|
71267
72650
|
const unit = await unitRowOf(deps, instance, body.unit);
|
|
71268
72651
|
if (!unit.ok) return unit.response;
|
|
71269
72652
|
const log = deps.log ?? console.log;
|
|
72653
|
+
const facts2 = await deps.fetchPrFacts({ repo: instance.repo, number: body.prNumber }).catch(() => void 0);
|
|
72654
|
+
if (facts2 === void 0) return json3(502, { ok: false, error: "github_unavailable", at });
|
|
72655
|
+
if (headBranchStateUnknown(facts2))
|
|
72656
|
+
return json3(502, {
|
|
72657
|
+
ok: false,
|
|
72658
|
+
error: "github_unavailable",
|
|
72659
|
+
message: headBranchStateError(instance.repo, body.prNumber),
|
|
72660
|
+
at
|
|
72661
|
+
});
|
|
72662
|
+
const pullRequest = pullRequestState(
|
|
72663
|
+
body.prNumber,
|
|
72664
|
+
unit.row?.pr?.url ?? `https://github.com/${instance.repo}/pull/${body.prNumber}`,
|
|
72665
|
+
facts2
|
|
72666
|
+
);
|
|
72667
|
+
if (pullRequest !== void 0 && (pullRequest.state !== "open" || pullRequest.headBranchExists === false || typeof pullRequest.headSha === "string" && !sameCommit(pullRequest.headSha, headSha)))
|
|
72668
|
+
return json3(200, { ok: true, pullRequest, at });
|
|
71270
72669
|
if (body.retry !== void 0 && body.refire !== void 0)
|
|
71271
72670
|
return json3(400, { ok: false, error: "checks recovery must be retry or refire, not both" });
|
|
71272
72671
|
if (body.retry !== void 0) {
|
|
@@ -71286,7 +72685,6 @@ async function checksStep(body, deps) {
|
|
|
71286
72685
|
);
|
|
71287
72686
|
return json3(200, { ok: true, refired, at });
|
|
71288
72687
|
}
|
|
71289
|
-
const facts2 = await deps.fetchPrFacts({ repo: instance.repo, number: body.prNumber }).catch(() => void 0);
|
|
71290
72688
|
let checks;
|
|
71291
72689
|
if (deps.fetchRoundChecks !== void 0) {
|
|
71292
72690
|
checks = await deps.fetchRoundChecks(instance.repo, headSha, body.prNumber, facts2?.baseRef).catch(() => void 0);
|
|
@@ -71307,7 +72705,8 @@ async function checksStep(body, deps) {
|
|
|
71307
72705
|
return json3(200, {
|
|
71308
72706
|
ok: true,
|
|
71309
72707
|
...checks !== void 0 ? { checks } : {},
|
|
71310
|
-
...
|
|
72708
|
+
...pullRequest !== void 0 ? { pullRequest } : {},
|
|
72709
|
+
...facts2.draft === true ? { draft: true } : {},
|
|
71311
72710
|
at
|
|
71312
72711
|
});
|
|
71313
72712
|
}
|
|
@@ -71458,6 +72857,8 @@ async function answerCoordinatorStep(door, body, deps) {
|
|
|
71458
72857
|
return spawn6(parsed.value, deps);
|
|
71459
72858
|
case "read-record":
|
|
71460
72859
|
return readRecord(parsed.value, deps);
|
|
72860
|
+
case "steer":
|
|
72861
|
+
return steerChild(parsed.value, deps);
|
|
71461
72862
|
case "pr-check":
|
|
71462
72863
|
return prCheck(parsed.value, deps);
|
|
71463
72864
|
case "round":
|
|
@@ -71505,7 +72906,7 @@ function createAdminCoordinatorHandler(deps) {
|
|
|
71505
72906
|
})();
|
|
71506
72907
|
};
|
|
71507
72908
|
}
|
|
71508
|
-
var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json3, describe11, isGenerated2, EVERY_RUN, REVIEW_POSTED_CHECKS, REVIEW_POSTED_RECHECK_MS, githubSecondStart, ROUND_OUTCOMES, ENDING_ICON, STEPS;
|
|
72909
|
+
var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json3, describe11, isGenerated2, EVERY_RUN, REVIEW_POSTED_CHECKS, REVIEW_POSTED_RECHECK_MS, githubSecondStart, CHILD_SUPERSESSION_REASONS, ROUND_OUTCOMES, ENDING_ICON, STEPS;
|
|
71509
72910
|
var init_adminCoordinator = __esm({
|
|
71510
72911
|
"../../src/channels/adminCoordinator.ts"() {
|
|
71511
72912
|
"use strict";
|
|
@@ -71558,6 +72959,7 @@ var init_adminCoordinator = __esm({
|
|
|
71558
72959
|
REVIEW_POSTED_CHECKS = 3;
|
|
71559
72960
|
REVIEW_POSTED_RECHECK_MS = 2e3;
|
|
71560
72961
|
githubSecondStart = (at) => Math.floor(at / SECOND_MS) * SECOND_MS;
|
|
72962
|
+
CHILD_SUPERSESSION_REASONS = /* @__PURE__ */ new Set(["merged", "closed", "head_moved", "branch_deleted"]);
|
|
71561
72963
|
ROUND_OUTCOMES = [
|
|
71562
72964
|
"started",
|
|
71563
72965
|
"pr_opened",
|
|
@@ -71589,6 +72991,7 @@ var init_adminCoordinator = __esm({
|
|
|
71589
72991
|
"branch",
|
|
71590
72992
|
"spawn",
|
|
71591
72993
|
"read-record",
|
|
72994
|
+
"steer",
|
|
71592
72995
|
"pr-check",
|
|
71593
72996
|
"round",
|
|
71594
72997
|
"unit-end",
|
|
@@ -71602,15 +73005,15 @@ var init_adminCoordinator = __esm({
|
|
|
71602
73005
|
});
|
|
71603
73006
|
|
|
71604
73007
|
// ../../src/core/coordinator/checksIntake.ts
|
|
71605
|
-
async function verifyWebhookSignature(secret2, rawBody,
|
|
73008
|
+
async function verifyWebhookSignature(secret2, rawBody, signature2) {
|
|
71606
73009
|
const key = await crypto.subtle.importKey("raw", encoder2.encode(secret2), { name: "HMAC", hash: "SHA-256" }, false, [
|
|
71607
73010
|
"sign"
|
|
71608
73011
|
]);
|
|
71609
73012
|
const digest = new Uint8Array(await crypto.subtle.sign("HMAC", key, encoder2.encode(rawBody)));
|
|
71610
73013
|
const expected = `sha256=${toHex(digest)}`;
|
|
71611
|
-
if (
|
|
73014
|
+
if (signature2.length !== expected.length) return false;
|
|
71612
73015
|
let diff = 0;
|
|
71613
|
-
for (let i = 0; i < expected.length; i++) diff |= expected.charCodeAt(i) ^
|
|
73016
|
+
for (let i = 0; i < expected.length; i++) diff |= expected.charCodeAt(i) ^ signature2.charCodeAt(i);
|
|
71614
73017
|
return diff === 0;
|
|
71615
73018
|
}
|
|
71616
73019
|
function createMergeWaitRegistry(ttlMs = MERGE_WAIT_TTL_MS) {
|
|
@@ -71639,14 +73042,14 @@ async function handleCheckRunIntake(headers, rawBody, deps) {
|
|
|
71639
73042
|
if (headers.signature === void 0 || !await verifyWebhookSignature(deps.secret, rawBody, headers.signature))
|
|
71640
73043
|
return { status: 401, body: { error: "unauthorized" } };
|
|
71641
73044
|
if (headers.event !== "check_run") return { status: 200, body: { ok: true, ignored: "event" } };
|
|
71642
|
-
let
|
|
73045
|
+
let payload2;
|
|
71643
73046
|
try {
|
|
71644
|
-
|
|
73047
|
+
payload2 = JSON.parse(rawBody);
|
|
71645
73048
|
} catch {
|
|
71646
73049
|
return { status: 400, body: { error: "invalid_json" } };
|
|
71647
73050
|
}
|
|
71648
|
-
if (typeof
|
|
71649
|
-
const p =
|
|
73051
|
+
if (typeof payload2 !== "object" || payload2 === null) return { status: 400, body: { error: "invalid_body" } };
|
|
73052
|
+
const p = payload2;
|
|
71650
73053
|
if (p.action !== "completed") return { status: 200, body: { ok: true, ignored: "action" } };
|
|
71651
73054
|
const headSha = p.check_run?.head_sha;
|
|
71652
73055
|
const repo = p.repository?.full_name;
|
|
@@ -71666,14 +73069,14 @@ async function handleIssueCommentIntake(headers, rawBody, deps) {
|
|
|
71666
73069
|
if (headers.signature === void 0 || !await verifyWebhookSignature(deps.secret, rawBody, headers.signature))
|
|
71667
73070
|
return { status: 401, body: { error: "unauthorized" } };
|
|
71668
73071
|
if (headers.event !== "issue_comment") return { status: 200, body: { ok: true, ignored: "event" } };
|
|
71669
|
-
let
|
|
73072
|
+
let payload2;
|
|
71670
73073
|
try {
|
|
71671
|
-
|
|
73074
|
+
payload2 = JSON.parse(rawBody);
|
|
71672
73075
|
} catch {
|
|
71673
73076
|
return { status: 400, body: { error: "invalid_json" } };
|
|
71674
73077
|
}
|
|
71675
|
-
if (typeof
|
|
71676
|
-
const p =
|
|
73078
|
+
if (typeof payload2 !== "object" || payload2 === null) return { status: 400, body: { error: "invalid_body" } };
|
|
73079
|
+
const p = payload2;
|
|
71677
73080
|
if (p.action !== "created") return { status: 200, body: { ok: true, ignored: "action" } };
|
|
71678
73081
|
if (p.issue?.pull_request === void 0) return { status: 200, body: { ok: true, ignored: "issue" } };
|
|
71679
73082
|
const repo = p.repository?.full_name;
|
|
@@ -71716,14 +73119,14 @@ async function handlePushIntake(headers, rawBody, deps) {
|
|
|
71716
73119
|
if (headers.signature === void 0 || !await verifyWebhookSignature(deps.secret, rawBody, headers.signature))
|
|
71717
73120
|
return { status: 401, body: { error: "unauthorized" } };
|
|
71718
73121
|
if (headers.event !== "push") return { status: 200, body: { ok: true, ignored: "event" } };
|
|
71719
|
-
let
|
|
73122
|
+
let payload2;
|
|
71720
73123
|
try {
|
|
71721
|
-
|
|
73124
|
+
payload2 = JSON.parse(rawBody);
|
|
71722
73125
|
} catch {
|
|
71723
73126
|
return { status: 400, body: { error: "invalid_json" } };
|
|
71724
73127
|
}
|
|
71725
|
-
if (typeof
|
|
71726
|
-
const p =
|
|
73128
|
+
if (typeof payload2 !== "object" || payload2 === null) return { status: 400, body: { error: "invalid_body" } };
|
|
73129
|
+
const p = payload2;
|
|
71727
73130
|
const repo = p.repository?.full_name;
|
|
71728
73131
|
if (typeof p.ref !== "string" || typeof repo !== "string" || repo === "")
|
|
71729
73132
|
return { status: 400, body: { error: "invalid_body" } };
|
|
@@ -72419,6 +73822,14 @@ async function runBot() {
|
|
|
72419
73822
|
...costsCfg?.prices ? { prices: costsCfg.prices } : {}
|
|
72420
73823
|
}) : null;
|
|
72421
73824
|
const coordinatorInstances = buildCoordinatorInstanceStore(runHistoryCfg, processSecrets);
|
|
73825
|
+
const decisionRecordAllocator = new DecisionRecordAllocator(
|
|
73826
|
+
fetchDecisionRecordClaims,
|
|
73827
|
+
async (repo, taskKey, claimed2, existing) => {
|
|
73828
|
+
const reserved = await coordinatorInstances.reserveDecisionRecord(repo, taskKey, claimed2, existing);
|
|
73829
|
+
if (!reserved.ok) throw new DecisionRecordReservationUnavailableError();
|
|
73830
|
+
return reserved.number;
|
|
73831
|
+
}
|
|
73832
|
+
);
|
|
72422
73833
|
let planeAdmitPass;
|
|
72423
73834
|
const planeEffectExecutor = {
|
|
72424
73835
|
draining: () => draining,
|
|
@@ -72520,6 +73931,7 @@ async function runBot() {
|
|
|
72520
73931
|
runHistoryWriter,
|
|
72521
73932
|
// The coordinator's instance records and unit rows (run-history items 49 and 50): what the ship branch writes when it hands an `agent:ship` request to the plan runner.
|
|
72522
73933
|
coordinatorInstances,
|
|
73934
|
+
reserveDecisionRecord: decisionRecordAllocator.reserve.bind(decisionRecordAllocator),
|
|
72523
73935
|
workflow: workflowSender,
|
|
72524
73936
|
runStore,
|
|
72525
73937
|
threadsElsewhere,
|
|
@@ -72681,7 +74093,9 @@ async function runBot() {
|
|
|
72681
74093
|
const out = await runLedger.recordIntake(key, receipt);
|
|
72682
74094
|
if (out === void 0) throw new Error("the receipt write degraded (the ledger warning names why)");
|
|
72683
74095
|
return out;
|
|
72684
|
-
}
|
|
74096
|
+
},
|
|
74097
|
+
claimIntakeDelivery: (key, poster, claimedAt) => ledgerClient.claimIntakeDelivery(key, poster, claimedAt),
|
|
74098
|
+
finishIntakeDelivery: (key, poster, delivered) => ledgerClient.finishIntakeDelivery(key, poster, delivered)
|
|
72685
74099
|
} : null;
|
|
72686
74100
|
slackIntake = wireIntakeGate({
|
|
72687
74101
|
intakeModeFor: (threadKey, userId, channelId) => config.intakeModeFor(threadKey, userId, channelId),
|
|
@@ -72792,7 +74206,12 @@ async function runBot() {
|
|
|
72792
74206
|
// and a park land on the write-through's plane routes, fire and forget —
|
|
72793
74207
|
// the null write-through swallows both where no ledger is configured.
|
|
72794
74208
|
plane: {
|
|
72795
|
-
level: (provider, side) => void runLedger.planeLevel({
|
|
74209
|
+
level: (provider, side, cause) => void runLedger.planeLevel({
|
|
74210
|
+
provider,
|
|
74211
|
+
name: "provider",
|
|
74212
|
+
side,
|
|
74213
|
+
...side === "down" && cause !== void 0 ? { cause } : {}
|
|
74214
|
+
}),
|
|
72796
74215
|
park: (runId3, provider) => void runLedger.planePark(runId3, provider)
|
|
72797
74216
|
}
|
|
72798
74217
|
});
|
|
@@ -72890,6 +74309,34 @@ async function runBot() {
|
|
|
72890
74309
|
registry: defaultRunRegistry,
|
|
72891
74310
|
ledgerRuns: () => runLedger.liveRuns(),
|
|
72892
74311
|
dispatch: (msg, io, opts) => dispatch(deps, msg, io, opts),
|
|
74312
|
+
steerChild: async (runId3, text, instance) => {
|
|
74313
|
+
const run2 = defaultRunRegistry.getById(runId3);
|
|
74314
|
+
if (!run2 || run2.finished || run2.threadKey === void 0 || run2.agent === void 0) return false;
|
|
74315
|
+
const outcome = await steerRun2(
|
|
74316
|
+
{
|
|
74317
|
+
// The coordinator already owns this admitted child; revoking its
|
|
74318
|
+
// stale PR authority is not a new request to run the agent.
|
|
74319
|
+
config: { canRunAgent: () => true, grantsFor: (id) => config.grantsFor(id) },
|
|
74320
|
+
runLedger,
|
|
74321
|
+
admission: defaultAdmission
|
|
74322
|
+
},
|
|
74323
|
+
{
|
|
74324
|
+
userId: instance.userId,
|
|
74325
|
+
channelId: instance.channelId,
|
|
74326
|
+
...instance.userName !== void 0 ? { userName: instance.userName } : {}
|
|
74327
|
+
},
|
|
74328
|
+
{
|
|
74329
|
+
runId: runId3,
|
|
74330
|
+
threadKey: run2.threadKey,
|
|
74331
|
+
agent: run2.agent,
|
|
74332
|
+
...run2.userId !== void 0 ? { requesterId: run2.userId } : {},
|
|
74333
|
+
...run2.parentRunId !== void 0 ? { parentRunId: run2.parentRunId } : {},
|
|
74334
|
+
...run2.parentInstanceId !== void 0 ? { parentInstanceId: run2.parentInstanceId } : {}
|
|
74335
|
+
},
|
|
74336
|
+
text
|
|
74337
|
+
);
|
|
74338
|
+
return outcome.kind === "steered";
|
|
74339
|
+
},
|
|
72893
74340
|
ioFor: (thread) => threadIoFor(thread),
|
|
72894
74341
|
findOpenPrByHead,
|
|
72895
74342
|
findMergedPrByHead,
|
|
@@ -73542,6 +74989,7 @@ var init_index = __esm({
|
|
|
73542
74989
|
init_authorBinding();
|
|
73543
74990
|
init_identityRewrite();
|
|
73544
74991
|
init_run2();
|
|
74992
|
+
init_decisionRecordReservation();
|
|
73545
74993
|
init_record();
|
|
73546
74994
|
init_admission();
|
|
73547
74995
|
init_scheduleStore();
|
|
@@ -73785,6 +75233,9 @@ var ConsoleIO = class _ConsoleIO {
|
|
|
73785
75233
|
* before that, and forever when no run was started (a config reply such as
|
|
73786
75234
|
* `help`, a refusal before a run existed). */
|
|
73787
75235
|
finished;
|
|
75236
|
+
/** A typed request failure that ended before a run existed, such as the
|
|
75237
|
+
* operator model refusing the one-shot ask. */
|
|
75238
|
+
failed = false;
|
|
73788
75239
|
/** How many child threads this one has opened; the next child's number. */
|
|
73789
75240
|
children = 0;
|
|
73790
75241
|
async reply(text) {
|
|
@@ -73802,6 +75253,9 @@ var ConsoleIO = class _ConsoleIO {
|
|
|
73802
75253
|
runFinished(receipt) {
|
|
73803
75254
|
this.finished = receipt;
|
|
73804
75255
|
}
|
|
75256
|
+
requestFailed() {
|
|
75257
|
+
this.failed = true;
|
|
75258
|
+
}
|
|
73805
75259
|
async status(initial) {
|
|
73806
75260
|
console.error(this.prefix + initial.title);
|
|
73807
75261
|
return {
|
|
@@ -73827,8 +75281,8 @@ var ConsoleIO = class _ConsoleIO {
|
|
|
73827
75281
|
};
|
|
73828
75282
|
}
|
|
73829
75283
|
};
|
|
73830
|
-
function askExitCode(finished) {
|
|
73831
|
-
return finished
|
|
75284
|
+
function askExitCode(finished, requestFailed = false) {
|
|
75285
|
+
return requestFailed || finished !== void 0 && finished.status !== "completed" ? 1 : 0;
|
|
73832
75286
|
}
|
|
73833
75287
|
function missingBotConfig(configPath) {
|
|
73834
75288
|
return new CommandError(
|
|
@@ -74001,7 +75455,7 @@ async function main() {
|
|
|
74001
75455
|
);
|
|
74002
75456
|
await runHistoryWriter.settled();
|
|
74003
75457
|
loopback.close();
|
|
74004
|
-
process.exitCode = askExitCode(io.finished);
|
|
75458
|
+
process.exitCode = askExitCode(io.finished, io.failed);
|
|
74005
75459
|
}
|
|
74006
75460
|
async function askLoopbackServer(input) {
|
|
74007
75461
|
const modelProxy = createModelProxyHandler({
|