@wolfx/oh-my-openagent 3.17.6-patch.1 → 3.17.10
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/features/background-agent/attempt-lifecycle.d.ts +12 -0
- package/dist/features/background-agent/background-task-notification-template.d.ts +2 -1
- package/dist/features/background-agent/constants.d.ts +1 -0
- package/dist/features/background-agent/fallback-retry-handler.d.ts +8 -0
- package/dist/features/background-agent/manager.d.ts +9 -0
- package/dist/features/background-agent/types.d.ts +24 -0
- package/dist/hooks/model-fallback/controller-accessor.d.ts +1 -0
- package/dist/hooks/model-fallback/fallback-state-controller.d.ts +1 -0
- package/dist/hooks/model-fallback/hook.d.ts +2 -1
- package/dist/hooks/preemptive-compaction-degradation-monitor.d.ts +1 -0
- package/dist/hooks/preemptive-compaction-no-text-tail.d.ts +1 -0
- package/dist/index.js +976 -314
- package/dist/plugin/event.d.ts +1 -0
- package/dist/shared/dynamic-truncator.d.ts +9 -10
- package/dist/shared/model-error-classifier.d.ts +2 -2
- package/dist/tools/background-task/clients.d.ts +1 -0
- package/dist/tools/delegate-task/builtin-categories.d.ts +1 -0
- package/dist/tools/delegate-task/builtin-category-definition.d.ts +1 -0
- package/dist/tools/delegate-task/constants.d.ts +1 -1
- package/dist/tools/delegate-task/executor-types.d.ts +1 -0
- package/dist/tools/delegate-task/openai-categories.d.ts +3 -0
- package/dist/tools/delegate-task/sync-task-fallback.d.ts +3 -0
- package/package.json +8 -5
package/dist/index.js
CHANGED
|
@@ -4446,6 +4446,56 @@ var require_picomatch2 = __commonJS((exports, module) => {
|
|
|
4446
4446
|
module.exports = picomatch;
|
|
4447
4447
|
});
|
|
4448
4448
|
|
|
4449
|
+
// src/agents/types.ts
|
|
4450
|
+
function extractModelName(model) {
|
|
4451
|
+
return model.includes("/") ? model.split("/").pop() ?? model : model;
|
|
4452
|
+
}
|
|
4453
|
+
function isGptModel(model) {
|
|
4454
|
+
const modelName = extractModelName(model).toLowerCase();
|
|
4455
|
+
return modelName.includes("gpt");
|
|
4456
|
+
}
|
|
4457
|
+
function isGptNativeSisyphusModel(model) {
|
|
4458
|
+
const modelName = extractModelName(model).toLowerCase();
|
|
4459
|
+
return GPT_NATIVE_SISYPHUS_RE.test(modelName);
|
|
4460
|
+
}
|
|
4461
|
+
function isGpt5_5Model(model) {
|
|
4462
|
+
const modelName = extractModelName(model).toLowerCase();
|
|
4463
|
+
return modelName.includes("gpt-5.5") || modelName.includes("gpt-5-5");
|
|
4464
|
+
}
|
|
4465
|
+
function isGpt5_3CodexModel(model) {
|
|
4466
|
+
const modelName = extractModelName(model).toLowerCase();
|
|
4467
|
+
return modelName.includes("gpt-5.3-codex") || modelName.includes("gpt-5-3-codex");
|
|
4468
|
+
}
|
|
4469
|
+
function isClaudeOpus47Model(model) {
|
|
4470
|
+
const modelName = extractModelName(model).toLowerCase().replaceAll(".", "-");
|
|
4471
|
+
return modelName.includes("claude-opus-4-7");
|
|
4472
|
+
}
|
|
4473
|
+
function isKimiK2Model(model) {
|
|
4474
|
+
const modelName = extractModelName(model).toLowerCase();
|
|
4475
|
+
if (modelName.includes("kimi"))
|
|
4476
|
+
return true;
|
|
4477
|
+
if (/k2[-.]?p[56]/.test(modelName))
|
|
4478
|
+
return true;
|
|
4479
|
+
return false;
|
|
4480
|
+
}
|
|
4481
|
+
function isGlmModel(model) {
|
|
4482
|
+
const modelName = extractModelName(model).toLowerCase();
|
|
4483
|
+
return modelName.includes("glm");
|
|
4484
|
+
}
|
|
4485
|
+
function isGeminiModel(model) {
|
|
4486
|
+
if (GEMINI_PROVIDERS.some((prefix) => model.startsWith(prefix)))
|
|
4487
|
+
return true;
|
|
4488
|
+
if (model.startsWith("github-copilot/") && extractModelName(model).toLowerCase().startsWith("gemini"))
|
|
4489
|
+
return true;
|
|
4490
|
+
const modelName = extractModelName(model).toLowerCase();
|
|
4491
|
+
return modelName.startsWith("gemini-");
|
|
4492
|
+
}
|
|
4493
|
+
var GPT_NATIVE_SISYPHUS_RE, GEMINI_PROVIDERS;
|
|
4494
|
+
var init_types = __esm(() => {
|
|
4495
|
+
GPT_NATIVE_SISYPHUS_RE = /gpt-5[.-](?:[4-9]|\d{2,})/i;
|
|
4496
|
+
GEMINI_PROVIDERS = ["google/", "google-vertex/"];
|
|
4497
|
+
});
|
|
4498
|
+
|
|
4449
4499
|
// src/hooks/ralph-loop/constants.ts
|
|
4450
4500
|
var HOOK_NAME3 = "ralph-loop", DEFAULT_STATE_FILE = ".sisyphus/ralph-loop.local.md", DEFAULT_MAX_ITERATIONS = 100, ULTRAWORK_MAX_ITERATIONS = 500, DEFAULT_COMPLETION_PROMISE = "DONE", ULTRAWORK_VERIFICATION_PROMISE = "VERIFIED";
|
|
4451
4501
|
var init_constants = () => {};
|
|
@@ -8035,6 +8085,12 @@ var init_kimi_categories = __esm(() => {
|
|
|
8035
8085
|
});
|
|
8036
8086
|
|
|
8037
8087
|
// src/tools/delegate-task/openai-categories.ts
|
|
8088
|
+
function resolveDeepCategoryPromptAppend(model) {
|
|
8089
|
+
if (model && isGpt5_5Model(model)) {
|
|
8090
|
+
return DEEP_CATEGORY_PROMPT_APPEND_GPT_5_5;
|
|
8091
|
+
}
|
|
8092
|
+
return DEEP_CATEGORY_PROMPT_APPEND;
|
|
8093
|
+
}
|
|
8038
8094
|
var ULTRABRAIN_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
8039
8095
|
You are working on DEEP LOGICAL REASONING / COMPLEX ARCHITECTURE tasks.
|
|
8040
8096
|
|
|
@@ -8074,6 +8130,26 @@ Genuinely independent tasks = flag and refuse, require separate delegations.
|
|
|
8074
8130
|
Approach: explore extensively, understand deeply, then act decisively. Prefer comprehensive solutions over quick patches. If the goal is unclear, make reasonable assumptions and proceed.
|
|
8075
8131
|
|
|
8076
8132
|
Minimal status updates. Focus on results, not play-by-play. Report completion with summary of changes.
|
|
8133
|
+
</Category_Context>`, DEEP_CATEGORY_PROMPT_APPEND_GPT_5_5 = `<Category_Context name="deep">
|
|
8134
|
+
You are operating in DEEP mode. This is the category reserved for goal-oriented autonomous work on hairy problems that reward thorough exploration and comprehensive solutions.
|
|
8135
|
+
|
|
8136
|
+
The orchestrator chose this category because the task benefits from depth over speed. You should feel empowered to spend the time needed: five to fifteen minutes of silent exploration before the first edit is normal and correct. Rushing to implementation on a deep task is a failure mode, not a feature.
|
|
8137
|
+
|
|
8138
|
+
# How deep mode adjusts the base behavior
|
|
8139
|
+
|
|
8140
|
+
**Exploration budget: generous.** Read the files you need, trace dependencies both directions, fire 2-5 explore/librarian sub-agents in parallel for broader questions. Build a complete mental model before the first \`apply_patch\`. Exploration here is an investment, not overhead.
|
|
8141
|
+
|
|
8142
|
+
**Goal, not plan.** You receive a GOAL describing the desired outcome. You figure out HOW to achieve it. The orchestrator deliberately did not hand you a step-by-step plan; producing one and asking for approval is not what was asked. Execute.
|
|
8143
|
+
|
|
8144
|
+
**Atomic task treatment.** When the goal contains numbered steps or phases, treat them as sub-steps of ONE task and execute them all in this turn. Splitting them across turns is wrong unless they reveal an architectural blocker that requires the user's input. If the "steps" turn out to be genuinely independent tasks that should have been separate delegations, flag that in your final message and refuse the ones beyond scope.
|
|
8145
|
+
|
|
8146
|
+
**Root cause bias.** Prefer root-cause fixes over symptom fixes. A null check around \`foo()\` is a symptom fix; fixing whatever causes \`foo()\` to return unexpected values is the root fix. Trace at least two levels up before settling on an answer. In deep mode, you have permission (and the expectation) to do the deeper fix.
|
|
8147
|
+
|
|
8148
|
+
**Ambition scaled to context.** For brand-new greenfield work, be ambitious. Choose strong defaults, avoid AI-slop aesthetics, produce something you would be proud to hand to another senior engineer. For changes in an existing codebase, be surgical and respect the existing patterns; depth does not mean invasiveness.
|
|
8149
|
+
|
|
8150
|
+
**Completion bar: full delivery.** "Simplified version", "proof of concept", and "you can extend this later" are not acceptable deliveries for a deep task. The orchestrator routed here specifically for a complete solution. If you hit a genuine blocker (missing secret, design decision only the user can make, three materially different attempts all failed), document it and return; otherwise, finish the task.
|
|
8151
|
+
|
|
8152
|
+
**Status cadence: sparse.** The user is not on the other side of this conversation; the orchestrator is, and they will synthesize your progress. Send commentary only at meaningful phase transitions (starting exploration, starting implementation, starting verification, hitting a genuine blocker). Do not narrate every tool call; silence during focused work is expected.
|
|
8077
8153
|
</Category_Context>`, QUICK_CATEGORY_PROMPT_APPEND = `<Category_Context>
|
|
8078
8154
|
You are working on SMALL / QUICK tasks.
|
|
8079
8155
|
|
|
@@ -8125,6 +8201,7 @@ EXPECTED OUTPUT:
|
|
|
8125
8201
|
If your prompt lacks this structure, REWRITE IT before delegating.
|
|
8126
8202
|
</Caller_Warning>`, OPENAI_CATEGORIES;
|
|
8127
8203
|
var init_openai_categories = __esm(() => {
|
|
8204
|
+
init_types();
|
|
8128
8205
|
OPENAI_CATEGORIES = [
|
|
8129
8206
|
{
|
|
8130
8207
|
name: "ultrabrain",
|
|
@@ -8136,7 +8213,8 @@ var init_openai_categories = __esm(() => {
|
|
|
8136
8213
|
name: "deep",
|
|
8137
8214
|
config: { model: "openai/gpt-5.5", variant: "medium" },
|
|
8138
8215
|
description: "Goal-oriented autonomous problem-solving. Thorough research before action. For hairy problems requiring deep understanding.",
|
|
8139
|
-
promptAppend: DEEP_CATEGORY_PROMPT_APPEND
|
|
8216
|
+
promptAppend: DEEP_CATEGORY_PROMPT_APPEND,
|
|
8217
|
+
resolvePromptAppend: resolveDeepCategoryPromptAppend
|
|
8140
8218
|
},
|
|
8141
8219
|
{
|
|
8142
8220
|
name: "quick",
|
|
@@ -8151,7 +8229,7 @@ var init_openai_categories = __esm(() => {
|
|
|
8151
8229
|
function buildCategoryRecord(selector) {
|
|
8152
8230
|
return Object.fromEntries(BUILTIN_CATEGORIES.map((definition) => [definition.name, selector(definition)]));
|
|
8153
8231
|
}
|
|
8154
|
-
var BUILTIN_CATEGORIES, DEFAULT_CATEGORIES, CATEGORY_PROMPT_APPENDS, CATEGORY_DESCRIPTIONS;
|
|
8232
|
+
var BUILTIN_CATEGORIES, DEFAULT_CATEGORIES, CATEGORY_PROMPT_APPENDS, CATEGORY_DESCRIPTIONS, CATEGORY_PROMPT_APPEND_RESOLVERS;
|
|
8155
8233
|
var init_builtin_categories = __esm(() => {
|
|
8156
8234
|
init_anthropic_categories();
|
|
8157
8235
|
init_google_categories();
|
|
@@ -8166,6 +8244,7 @@ var init_builtin_categories = __esm(() => {
|
|
|
8166
8244
|
DEFAULT_CATEGORIES = buildCategoryRecord((definition) => definition.config);
|
|
8167
8245
|
CATEGORY_PROMPT_APPENDS = buildCategoryRecord((definition) => definition.promptAppend);
|
|
8168
8246
|
CATEGORY_DESCRIPTIONS = buildCategoryRecord((definition) => definition.description);
|
|
8247
|
+
CATEGORY_PROMPT_APPEND_RESOLVERS = Object.fromEntries(BUILTIN_CATEGORIES.filter((definition) => definition.resolvePromptAppend !== undefined).map((definition) => [definition.name, definition.resolvePromptAppend]));
|
|
8169
8248
|
});
|
|
8170
8249
|
|
|
8171
8250
|
// src/tools/delegate-task/constants.ts
|
|
@@ -15921,6 +16000,41 @@ function normalizeSDKResponse(response, fallback, options) {
|
|
|
15921
16000
|
// src/shared/dynamic-truncator.ts
|
|
15922
16001
|
var CHARS_PER_TOKEN_ESTIMATE = 4;
|
|
15923
16002
|
var DEFAULT_TARGET_MAX_TOKENS = 50000;
|
|
16003
|
+
var usageCacheByClient = new WeakMap;
|
|
16004
|
+
function createModelCacheKey(modelCacheState) {
|
|
16005
|
+
if (!modelCacheState) {
|
|
16006
|
+
return "default";
|
|
16007
|
+
}
|
|
16008
|
+
const cachedLimits = modelCacheState.modelContextLimitsCache ? [...modelCacheState.modelContextLimitsCache.entries()].sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey)).map(([modelKey, limit]) => `${modelKey}:${limit}`).join(",") : "";
|
|
16009
|
+
return `${modelCacheState.anthropicContext1MEnabled ? "1m" : "200k"}|${cachedLimits}`;
|
|
16010
|
+
}
|
|
16011
|
+
function getUsageCache(client, modelCacheState) {
|
|
16012
|
+
let cacheByModelState = usageCacheByClient.get(client);
|
|
16013
|
+
if (!cacheByModelState) {
|
|
16014
|
+
cacheByModelState = new Map;
|
|
16015
|
+
usageCacheByClient.set(client, cacheByModelState);
|
|
16016
|
+
}
|
|
16017
|
+
const modelCacheKey = createModelCacheKey(modelCacheState);
|
|
16018
|
+
let cache = cacheByModelState.get(modelCacheKey);
|
|
16019
|
+
if (!cache) {
|
|
16020
|
+
cache = new Map;
|
|
16021
|
+
cacheByModelState.set(modelCacheKey, cache);
|
|
16022
|
+
}
|
|
16023
|
+
return cache;
|
|
16024
|
+
}
|
|
16025
|
+
function invalidateContextWindowUsageCache(ctx, sessionID) {
|
|
16026
|
+
const cacheByModelState = usageCacheByClient.get(ctx.client);
|
|
16027
|
+
if (!cacheByModelState) {
|
|
16028
|
+
return;
|
|
16029
|
+
}
|
|
16030
|
+
for (const cache of cacheByModelState.values()) {
|
|
16031
|
+
if (sessionID) {
|
|
16032
|
+
cache.delete(sessionID);
|
|
16033
|
+
} else {
|
|
16034
|
+
cache.clear();
|
|
16035
|
+
}
|
|
16036
|
+
}
|
|
16037
|
+
}
|
|
15924
16038
|
function estimateTokens(text) {
|
|
15925
16039
|
return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);
|
|
15926
16040
|
}
|
|
@@ -15982,6 +16096,16 @@ function truncateToTokenLimit(output, maxTokens, preserveHeaderLines = 3) {
|
|
|
15982
16096
|
};
|
|
15983
16097
|
}
|
|
15984
16098
|
async function getContextWindowUsage(ctx, sessionID, modelCacheState) {
|
|
16099
|
+
const cache = getUsageCache(ctx.client, modelCacheState);
|
|
16100
|
+
const cached = cache.get(sessionID);
|
|
16101
|
+
if (cached) {
|
|
16102
|
+
return cached;
|
|
16103
|
+
}
|
|
16104
|
+
const usagePromise = fetchContextWindowUsage(ctx, sessionID, modelCacheState);
|
|
16105
|
+
cache.set(sessionID, usagePromise);
|
|
16106
|
+
return usagePromise;
|
|
16107
|
+
}
|
|
16108
|
+
async function fetchContextWindowUsage(ctx, sessionID, modelCacheState) {
|
|
15985
16109
|
try {
|
|
15986
16110
|
const response = await ctx.client.session.messages({
|
|
15987
16111
|
path: { id: sessionID }
|
|
@@ -66161,7 +66285,9 @@ var RETRYABLE_MESSAGE_PATTERNS = [
|
|
|
66161
66285
|
"502",
|
|
66162
66286
|
"504",
|
|
66163
66287
|
"429",
|
|
66164
|
-
"529"
|
|
66288
|
+
"529",
|
|
66289
|
+
"403",
|
|
66290
|
+
"forbidden"
|
|
66165
66291
|
];
|
|
66166
66292
|
var STOP_MESSAGE_PATTERNS = [
|
|
66167
66293
|
"quota will reset after",
|
|
@@ -66541,14 +66667,12 @@ async function handleSessionIdle(args) {
|
|
|
66541
66667
|
return;
|
|
66542
66668
|
}
|
|
66543
66669
|
if (!todos || todos.length === 0) {
|
|
66544
|
-
sessionStateStore.resetContinuationProgress(sessionID);
|
|
66545
66670
|
sessionStateStore.resetContinuationProgress(sessionID);
|
|
66546
66671
|
log(`[${HOOK_NAME}] No todos`, { sessionID });
|
|
66547
66672
|
return;
|
|
66548
66673
|
}
|
|
66549
66674
|
const incompleteCount = getIncompleteCount(todos);
|
|
66550
66675
|
if (incompleteCount === 0) {
|
|
66551
|
-
sessionStateStore.resetContinuationProgress(sessionID);
|
|
66552
66676
|
sessionStateStore.resetContinuationProgress(sessionID);
|
|
66553
66677
|
log(`[${HOOK_NAME}] All todos complete`, { sessionID, total: todos.length });
|
|
66554
66678
|
return;
|
|
@@ -85184,17 +85308,21 @@ function createModelFallbackStateController(input) {
|
|
|
85184
85308
|
function setSessionFallbackChain(sessionID, fallbackChain) {
|
|
85185
85309
|
if (!sessionID)
|
|
85186
85310
|
return;
|
|
85187
|
-
sessionFallbackChains.set(sessionID, fallbackChain?.length ? fallbackChain : []);
|
|
85311
|
+
sessionFallbackChains.set(sessionID, fallbackChain?.length ? [...fallbackChain] : []);
|
|
85188
85312
|
}
|
|
85189
85313
|
function clearSessionFallbackChain(sessionID) {
|
|
85190
85314
|
sessionFallbackChains.delete(sessionID);
|
|
85191
85315
|
}
|
|
85316
|
+
function getSessionFallbackChain(sessionID) {
|
|
85317
|
+
const fallbackChain = sessionFallbackChains.get(sessionID);
|
|
85318
|
+
return fallbackChain ? [...fallbackChain] : undefined;
|
|
85319
|
+
}
|
|
85192
85320
|
function setPendingModelFallback(sessionID, agentName, currentProviderID, currentModelID) {
|
|
85193
85321
|
const agentKey = getAgentConfigKey(agentName);
|
|
85194
85322
|
const requirements = AGENT_MODEL_REQUIREMENTS[agentKey];
|
|
85195
85323
|
const fallbackChain = sessionFallbackChains.get(sessionID) ?? requirements?.fallbackChain;
|
|
85196
85324
|
if (!fallbackChain?.length) {
|
|
85197
|
-
log(
|
|
85325
|
+
log(`[model-fallback] No fallback chain for agent: ${agentName} (key: ${agentKey})`);
|
|
85198
85326
|
return false;
|
|
85199
85327
|
}
|
|
85200
85328
|
const existing = pendingModelFallbacks.get(sessionID);
|
|
@@ -85206,21 +85334,21 @@ function createModelFallbackStateController(input) {
|
|
|
85206
85334
|
attemptCount: 0,
|
|
85207
85335
|
pending: true
|
|
85208
85336
|
});
|
|
85209
|
-
log(
|
|
85337
|
+
log(`[model-fallback] Set pending fallback for session: ${sessionID}, agent: ${agentName}`);
|
|
85210
85338
|
return true;
|
|
85211
85339
|
}
|
|
85212
85340
|
if (existing.pending) {
|
|
85213
|
-
log(
|
|
85341
|
+
log(`[model-fallback] Pending fallback already armed for session: ${sessionID}`);
|
|
85214
85342
|
return false;
|
|
85215
85343
|
}
|
|
85216
85344
|
existing.providerID = currentProviderID;
|
|
85217
85345
|
existing.modelID = currentModelID;
|
|
85218
85346
|
existing.pending = true;
|
|
85219
85347
|
if (existing.attemptCount >= existing.fallbackChain.length) {
|
|
85220
|
-
log(
|
|
85348
|
+
log(`[model-fallback] Fallback chain exhausted for session: ${sessionID}`);
|
|
85221
85349
|
return false;
|
|
85222
85350
|
}
|
|
85223
|
-
log(
|
|
85351
|
+
log(`[model-fallback] Re-armed pending fallback for session: ${sessionID}`);
|
|
85224
85352
|
return true;
|
|
85225
85353
|
}
|
|
85226
85354
|
function getNextFallback2(sessionID) {
|
|
@@ -85230,7 +85358,7 @@ function createModelFallbackStateController(input) {
|
|
|
85230
85358
|
const fallback = getNextReachableFallback(sessionID, state3);
|
|
85231
85359
|
if (fallback)
|
|
85232
85360
|
return fallback;
|
|
85233
|
-
log(
|
|
85361
|
+
log(`[model-fallback] No more fallbacks for session: ${sessionID}`);
|
|
85234
85362
|
pendingModelFallbacks.delete(sessionID);
|
|
85235
85363
|
return null;
|
|
85236
85364
|
}
|
|
@@ -85252,6 +85380,7 @@ function createModelFallbackStateController(input) {
|
|
|
85252
85380
|
return {
|
|
85253
85381
|
lastToastKey,
|
|
85254
85382
|
setSessionFallbackChain,
|
|
85383
|
+
getSessionFallbackChain,
|
|
85255
85384
|
clearSessionFallbackChain,
|
|
85256
85385
|
setPendingModelFallback,
|
|
85257
85386
|
getNextFallback: getNextFallback2,
|
|
@@ -85293,6 +85422,7 @@ function createModelFallbackHook(args) {
|
|
|
85293
85422
|
return {
|
|
85294
85423
|
lastToastKey: controller.lastToastKey,
|
|
85295
85424
|
setSessionFallbackChain: controller.setSessionFallbackChain,
|
|
85425
|
+
getSessionFallbackChain: controller.getSessionFallbackChain,
|
|
85296
85426
|
clearSessionFallbackChain: controller.clearSessionFallbackChain,
|
|
85297
85427
|
setPendingModelFallback: controller.setPendingModelFallback,
|
|
85298
85428
|
getNextFallback: controller.getNextFallback,
|
|
@@ -87604,13 +87734,6 @@ function readPackageVersion(packageJsonPath) {
|
|
|
87604
87734
|
return pkg.version ?? null;
|
|
87605
87735
|
}
|
|
87606
87736
|
function getCachedVersion() {
|
|
87607
|
-
for (const candidate of INSTALLED_PACKAGE_JSON_CANDIDATES) {
|
|
87608
|
-
try {
|
|
87609
|
-
if (fs12.existsSync(candidate)) {
|
|
87610
|
-
return readPackageVersion(candidate);
|
|
87611
|
-
}
|
|
87612
|
-
} catch {}
|
|
87613
|
-
}
|
|
87614
87737
|
try {
|
|
87615
87738
|
const currentDir = path10.dirname(fileURLToPath3(import.meta.url));
|
|
87616
87739
|
const pkgPath = findPackageJsonUp(currentDir);
|
|
@@ -87620,6 +87743,13 @@ function getCachedVersion() {
|
|
|
87620
87743
|
} catch (err) {
|
|
87621
87744
|
log("[auto-update-checker] Failed to resolve version from current directory:", err);
|
|
87622
87745
|
}
|
|
87746
|
+
for (const candidate of INSTALLED_PACKAGE_JSON_CANDIDATES) {
|
|
87747
|
+
try {
|
|
87748
|
+
if (fs12.existsSync(candidate)) {
|
|
87749
|
+
return readPackageVersion(candidate);
|
|
87750
|
+
}
|
|
87751
|
+
} catch {}
|
|
87752
|
+
}
|
|
87623
87753
|
try {
|
|
87624
87754
|
const execDir = path10.dirname(fs12.realpathSync(process.execPath));
|
|
87625
87755
|
const pkgPath = findPackageJsonUp(execDir);
|
|
@@ -88547,54 +88677,8 @@ function createAgentUsageReminderHook(_ctx) {
|
|
|
88547
88677
|
event: eventHandler
|
|
88548
88678
|
};
|
|
88549
88679
|
}
|
|
88550
|
-
// src/agents/types.ts
|
|
88551
|
-
function extractModelName(model) {
|
|
88552
|
-
return model.includes("/") ? model.split("/").pop() ?? model : model;
|
|
88553
|
-
}
|
|
88554
|
-
function isGptModel(model) {
|
|
88555
|
-
const modelName = extractModelName(model).toLowerCase();
|
|
88556
|
-
return modelName.includes("gpt");
|
|
88557
|
-
}
|
|
88558
|
-
var GPT_NATIVE_SISYPHUS_RE = /gpt-5[.-](?:[4-9]|\d{2,})/i;
|
|
88559
|
-
function isGptNativeSisyphusModel(model) {
|
|
88560
|
-
const modelName = extractModelName(model).toLowerCase();
|
|
88561
|
-
return GPT_NATIVE_SISYPHUS_RE.test(modelName);
|
|
88562
|
-
}
|
|
88563
|
-
function isGpt5_5Model(model) {
|
|
88564
|
-
const modelName = extractModelName(model).toLowerCase();
|
|
88565
|
-
return modelName.includes("gpt-5.5") || modelName.includes("gpt-5-5");
|
|
88566
|
-
}
|
|
88567
|
-
function isGpt5_3CodexModel(model) {
|
|
88568
|
-
const modelName = extractModelName(model).toLowerCase();
|
|
88569
|
-
return modelName.includes("gpt-5.3-codex") || modelName.includes("gpt-5-3-codex");
|
|
88570
|
-
}
|
|
88571
|
-
function isClaudeOpus47Model(model) {
|
|
88572
|
-
const modelName = extractModelName(model).toLowerCase().replaceAll(".", "-");
|
|
88573
|
-
return modelName.includes("claude-opus-4-7");
|
|
88574
|
-
}
|
|
88575
|
-
function isKimiK2Model(model) {
|
|
88576
|
-
const modelName = extractModelName(model).toLowerCase();
|
|
88577
|
-
if (modelName.includes("kimi"))
|
|
88578
|
-
return true;
|
|
88579
|
-
if (/k2[-.]?p[56]/.test(modelName))
|
|
88580
|
-
return true;
|
|
88581
|
-
return false;
|
|
88582
|
-
}
|
|
88583
|
-
var GEMINI_PROVIDERS = ["google/", "google-vertex/"];
|
|
88584
|
-
function isGlmModel(model) {
|
|
88585
|
-
const modelName = extractModelName(model).toLowerCase();
|
|
88586
|
-
return modelName.includes("glm");
|
|
88587
|
-
}
|
|
88588
|
-
function isGeminiModel(model) {
|
|
88589
|
-
if (GEMINI_PROVIDERS.some((prefix) => model.startsWith(prefix)))
|
|
88590
|
-
return true;
|
|
88591
|
-
if (model.startsWith("github-copilot/") && extractModelName(model).toLowerCase().startsWith("gemini"))
|
|
88592
|
-
return true;
|
|
88593
|
-
const modelName = extractModelName(model).toLowerCase();
|
|
88594
|
-
return modelName.startsWith("gemini-");
|
|
88595
|
-
}
|
|
88596
|
-
|
|
88597
88680
|
// src/hooks/keyword-detector/ultrawork/source-detector.ts
|
|
88681
|
+
init_types();
|
|
88598
88682
|
function isPlannerAgent(agentName) {
|
|
88599
88683
|
if (!agentName)
|
|
88600
88684
|
return false;
|
|
@@ -91455,6 +91539,7 @@ function createRalphLoopHook(ctx, options) {
|
|
|
91455
91539
|
};
|
|
91456
91540
|
}
|
|
91457
91541
|
// src/hooks/no-sisyphus-gpt/hook.ts
|
|
91542
|
+
init_types();
|
|
91458
91543
|
init_agent_display_names();
|
|
91459
91544
|
var TOAST_TITLE = "NEVER Use Sisyphus with GPT";
|
|
91460
91545
|
var TOAST_MESSAGE = [
|
|
@@ -91510,6 +91595,7 @@ function createNoSisyphusGptHook(ctx) {
|
|
|
91510
91595
|
};
|
|
91511
91596
|
}
|
|
91512
91597
|
// src/hooks/no-hephaestus-non-gpt/hook.ts
|
|
91598
|
+
init_types();
|
|
91513
91599
|
init_agent_display_names();
|
|
91514
91600
|
var TOAST_TITLE2 = "NEVER Use Hephaestus with Non-GPT";
|
|
91515
91601
|
var TOAST_MESSAGE2 = [
|
|
@@ -101328,7 +101414,10 @@ function findMessageByID(messages, messageID) {
|
|
|
101328
101414
|
return messages.find((message) => message.info?.id === messageID);
|
|
101329
101415
|
}
|
|
101330
101416
|
async function resolveNoTextTailFromSession(args) {
|
|
101331
|
-
const { client, sessionID, messageID, directory } = args;
|
|
101417
|
+
const { client, sessionID, messageID, directory, parts } = args;
|
|
101418
|
+
if (Array.isArray(parts)) {
|
|
101419
|
+
return isStepOnlyNoTextParts(parts);
|
|
101420
|
+
}
|
|
101332
101421
|
try {
|
|
101333
101422
|
const response = await client.session.messages({
|
|
101334
101423
|
path: { id: sessionID },
|
|
@@ -101455,7 +101544,8 @@ function createPostCompactionDegradationMonitor(args) {
|
|
|
101455
101544
|
client,
|
|
101456
101545
|
sessionID: info.sessionID,
|
|
101457
101546
|
messageID: info.id,
|
|
101458
|
-
directory
|
|
101547
|
+
directory,
|
|
101548
|
+
parts: info.parts
|
|
101459
101549
|
});
|
|
101460
101550
|
if (!isNoTextTail) {
|
|
101461
101551
|
postCompactionNoTextStreak.set(info.sessionID, 0);
|
|
@@ -101619,7 +101709,8 @@ function createPreemptiveCompactionHook(ctx, pluginConfig, modelCacheState) {
|
|
|
101619
101709
|
compactedSessions.delete(info.sessionID);
|
|
101620
101710
|
await postCompactionMonitor.onAssistantMessageUpdated({
|
|
101621
101711
|
sessionID: info.sessionID,
|
|
101622
|
-
id: info.id
|
|
101712
|
+
id: info.id,
|
|
101713
|
+
parts: info.parts
|
|
101623
101714
|
});
|
|
101624
101715
|
}
|
|
101625
101716
|
};
|
|
@@ -102216,7 +102307,7 @@ function classifyErrorType(error48) {
|
|
|
102216
102307
|
if (errorName?.includes("providermodelnotfounderror") || errorName?.includes("modelnotfounderror") || errorName?.includes("unknownerror") && /model\s+not\s+found/i.test(message)) {
|
|
102217
102308
|
return "model_not_found";
|
|
102218
102309
|
}
|
|
102219
|
-
if (errorName?.includes("quotaexceeded") || errorName?.includes("insufficientquota") || errorName?.includes("billingerror") || /quota.?exceeded/i.test(message) || /subscription.*quota/i.test(message) || /insufficient.?quota/i.test(message) || /billing.?(?:hard.?)?limit/i.test(message) || /exhausted\s+your\s+capacity/i.test(message) || /out\s+of\s+credits?/i.test(message) || /payment.?required/i.test(message) || /usage\s+limit/i.test(message)) {
|
|
102310
|
+
if (errorName?.includes("quotaexceeded") || errorName?.includes("insufficientquota") || errorName?.includes("billingerror") || /quota.?exceeded/i.test(message) || /subscription.*quota/i.test(message) || /insufficient.?(?:quota|balance|funds?)/i.test(message) || /billing.?(?:hard.?)?limit/i.test(message) || /exhausted\s+your\s+capacity/i.test(message) || /out\s+of\s+credits?/i.test(message) || /payment.?required/i.test(message) || /usage\s+limit/i.test(message)) {
|
|
102220
102311
|
return "quota_exceeded";
|
|
102221
102312
|
}
|
|
102222
102313
|
return;
|
|
@@ -102244,8 +102335,7 @@ function isRetryableError(error48, retryOnErrors) {
|
|
|
102244
102335
|
return true;
|
|
102245
102336
|
}
|
|
102246
102337
|
if (errorType === "quota_exceeded") {
|
|
102247
|
-
|
|
102248
|
-
return hasAutoRetrySignal;
|
|
102338
|
+
return true;
|
|
102249
102339
|
}
|
|
102250
102340
|
if (statusCode && retryOnErrors.includes(statusCode)) {
|
|
102251
102341
|
return true;
|
|
@@ -103334,6 +103424,19 @@ function extractFilePath(metadata) {
|
|
|
103334
103424
|
}
|
|
103335
103425
|
return;
|
|
103336
103426
|
}
|
|
103427
|
+
function extractLineCount(metadata) {
|
|
103428
|
+
if (!metadata || typeof metadata !== "object") {
|
|
103429
|
+
return;
|
|
103430
|
+
}
|
|
103431
|
+
const objectMeta = metadata;
|
|
103432
|
+
const candidates = [objectMeta.lineCount, objectMeta.linesWritten, objectMeta.lines];
|
|
103433
|
+
for (const candidate of candidates) {
|
|
103434
|
+
if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 0) {
|
|
103435
|
+
return candidate;
|
|
103436
|
+
}
|
|
103437
|
+
}
|
|
103438
|
+
return;
|
|
103439
|
+
}
|
|
103337
103440
|
async function appendWriteHashlineOutput(output) {
|
|
103338
103441
|
if (output.output.startsWith(WRITE_SUCCESS_MARKER)) {
|
|
103339
103442
|
return;
|
|
@@ -103342,6 +103445,11 @@ async function appendWriteHashlineOutput(output) {
|
|
|
103342
103445
|
if (outputLower.startsWith("error") || outputLower.includes("failed")) {
|
|
103343
103446
|
return;
|
|
103344
103447
|
}
|
|
103448
|
+
const metadataLineCount = extractLineCount(output.metadata);
|
|
103449
|
+
if (metadataLineCount !== undefined) {
|
|
103450
|
+
output.output = `${WRITE_SUCCESS_MARKER} ${metadataLineCount} lines written.`;
|
|
103451
|
+
return;
|
|
103452
|
+
}
|
|
103345
103453
|
const filePath = extractFilePath(output.metadata);
|
|
103346
103454
|
if (!filePath) {
|
|
103347
103455
|
return;
|
|
@@ -122011,6 +122119,83 @@ async function formatFullSession(task, client2, options) {
|
|
|
122011
122119
|
`);
|
|
122012
122120
|
}
|
|
122013
122121
|
|
|
122122
|
+
// src/features/background-agent/error-classifier.ts
|
|
122123
|
+
function isRecord15(value) {
|
|
122124
|
+
return typeof value === "object" && value !== null;
|
|
122125
|
+
}
|
|
122126
|
+
function isAbortedSessionError(error92) {
|
|
122127
|
+
const message = getErrorText(error92);
|
|
122128
|
+
return message.toLowerCase().includes("aborted");
|
|
122129
|
+
}
|
|
122130
|
+
function getErrorText(error92) {
|
|
122131
|
+
if (!error92)
|
|
122132
|
+
return "";
|
|
122133
|
+
if (typeof error92 === "string")
|
|
122134
|
+
return error92;
|
|
122135
|
+
if (error92 instanceof Error) {
|
|
122136
|
+
return `${error92.name}: ${error92.message}`;
|
|
122137
|
+
}
|
|
122138
|
+
if (typeof error92 === "object" && error92 !== null) {
|
|
122139
|
+
if ("message" in error92 && typeof error92.message === "string") {
|
|
122140
|
+
return error92.message;
|
|
122141
|
+
}
|
|
122142
|
+
if ("name" in error92 && typeof error92.name === "string") {
|
|
122143
|
+
return error92.name;
|
|
122144
|
+
}
|
|
122145
|
+
}
|
|
122146
|
+
return "";
|
|
122147
|
+
}
|
|
122148
|
+
function extractErrorName2(error92) {
|
|
122149
|
+
if (isRecord15(error92) && typeof error92["name"] === "string")
|
|
122150
|
+
return error92["name"];
|
|
122151
|
+
if (error92 instanceof Error)
|
|
122152
|
+
return error92.name;
|
|
122153
|
+
return;
|
|
122154
|
+
}
|
|
122155
|
+
function extractErrorMessage(error92) {
|
|
122156
|
+
if (!error92)
|
|
122157
|
+
return;
|
|
122158
|
+
if (typeof error92 === "string")
|
|
122159
|
+
return error92;
|
|
122160
|
+
if (isRecord15(error92)) {
|
|
122161
|
+
const dataRaw = error92["data"];
|
|
122162
|
+
const candidates = [
|
|
122163
|
+
dataRaw,
|
|
122164
|
+
isRecord15(dataRaw) ? dataRaw["error"] : undefined,
|
|
122165
|
+
error92["error"],
|
|
122166
|
+
error92["cause"],
|
|
122167
|
+
error92
|
|
122168
|
+
];
|
|
122169
|
+
for (const candidate of candidates) {
|
|
122170
|
+
if (typeof candidate === "string" && candidate.length > 0)
|
|
122171
|
+
return candidate;
|
|
122172
|
+
if (isRecord15(candidate) && typeof candidate["message"] === "string" && candidate["message"].length > 0) {
|
|
122173
|
+
return candidate["message"];
|
|
122174
|
+
}
|
|
122175
|
+
}
|
|
122176
|
+
}
|
|
122177
|
+
if (error92 instanceof Error)
|
|
122178
|
+
return error92.message;
|
|
122179
|
+
try {
|
|
122180
|
+
return JSON.stringify(error92);
|
|
122181
|
+
} catch {
|
|
122182
|
+
return String(error92);
|
|
122183
|
+
}
|
|
122184
|
+
}
|
|
122185
|
+
function getSessionErrorMessage(properties) {
|
|
122186
|
+
const errorRaw = properties["error"];
|
|
122187
|
+
if (!isRecord15(errorRaw))
|
|
122188
|
+
return;
|
|
122189
|
+
const dataRaw = errorRaw["data"];
|
|
122190
|
+
if (isRecord15(dataRaw)) {
|
|
122191
|
+
const message2 = dataRaw["message"];
|
|
122192
|
+
if (typeof message2 === "string")
|
|
122193
|
+
return message2;
|
|
122194
|
+
}
|
|
122195
|
+
const message = errorRaw["message"];
|
|
122196
|
+
return typeof message === "string" ? message : undefined;
|
|
122197
|
+
}
|
|
122198
|
+
|
|
122014
122199
|
// src/tools/background-task/task-result-format.ts
|
|
122015
122200
|
function getTimeString(value) {
|
|
122016
122201
|
return typeof value === "string" ? value : "";
|
|
@@ -122057,6 +122242,19 @@ Session ID: ${task.sessionID}
|
|
|
122057
122242
|
const timeB = getTimeString(b.info?.time);
|
|
122058
122243
|
return timeA.localeCompare(timeB);
|
|
122059
122244
|
});
|
|
122245
|
+
const sessionError = sortedMessages.filter((message) => message.info?.role === "assistant" && message.info?.error).map((message) => extractErrorMessage(message.info?.error)).find((message) => typeof message === "string" && message.length > 0);
|
|
122246
|
+
if (sessionError) {
|
|
122247
|
+
return `Task Result
|
|
122248
|
+
|
|
122249
|
+
Task ID: ${task.id}
|
|
122250
|
+
Description: ${task.description}
|
|
122251
|
+
Duration: ${formatDuration(task.startedAt ?? new Date, task.completedAt)}
|
|
122252
|
+
Session ID: ${task.sessionID}
|
|
122253
|
+
|
|
122254
|
+
---
|
|
122255
|
+
|
|
122256
|
+
Session error: ${sessionError}`;
|
|
122257
|
+
}
|
|
122060
122258
|
const newMessages = consumeNewMessages(task.sessionID, sortedMessages);
|
|
122061
122259
|
if (newMessages.length === 0) {
|
|
122062
122260
|
const duration6 = formatDuration(task.startedAt ?? new Date, task.completedAt);
|
|
@@ -123984,6 +124182,18 @@ async function fetchSessionMessages(client2, sessionID) {
|
|
|
123984
124182
|
const rawData = messagesResult?.data ?? messagesResult;
|
|
123985
124183
|
return Array.isArray(rawData) ? rawData : [];
|
|
123986
124184
|
}
|
|
124185
|
+
function getTerminalSessionError(messages) {
|
|
124186
|
+
const lastAssistant = [...messages].reverse().find((msg) => msg.info?.role === "assistant");
|
|
124187
|
+
const lastUser = [...messages].reverse().find((msg) => msg.info?.role === "user");
|
|
124188
|
+
if (lastUser?.info?.id && lastAssistant?.info?.id && lastAssistant.info.id <= lastUser.info.id) {
|
|
124189
|
+
return null;
|
|
124190
|
+
}
|
|
124191
|
+
if (!lastAssistant?.info || !("error" in lastAssistant.info)) {
|
|
124192
|
+
return null;
|
|
124193
|
+
}
|
|
124194
|
+
const errorMessage = extractErrorMessage(lastAssistant.info.error);
|
|
124195
|
+
return errorMessage && errorMessage.length > 0 ? errorMessage : "Session error";
|
|
124196
|
+
}
|
|
123987
124197
|
function isSessionComplete(messages) {
|
|
123988
124198
|
let lastUser;
|
|
123989
124199
|
let lastAssistant;
|
|
@@ -124072,6 +124282,11 @@ Session ID: ${input.sessionID}`;
|
|
|
124072
124282
|
if (input.anchorMessageCount !== undefined && messages.length <= input.anchorMessageCount) {
|
|
124073
124283
|
continue;
|
|
124074
124284
|
}
|
|
124285
|
+
const sessionError = getTerminalSessionError(messages);
|
|
124286
|
+
if (sessionError) {
|
|
124287
|
+
log("[task] Poll detected terminal session error", { sessionID: input.sessionID, sessionError });
|
|
124288
|
+
return sessionError;
|
|
124289
|
+
}
|
|
124075
124290
|
if (isSessionComplete(messages)) {
|
|
124076
124291
|
log("[task] Poll complete - terminal finish detected", { sessionID: input.sessionID, pollCount });
|
|
124077
124292
|
break;
|
|
@@ -124840,7 +125055,8 @@ async function retrySyncPromptWithFallbacks(input) {
|
|
|
124840
125055
|
if (!categoryModel || !fallbackChain || fallbackChain.length === 0) {
|
|
124841
125056
|
return {
|
|
124842
125057
|
promptError: initialError,
|
|
124843
|
-
categoryModel
|
|
125058
|
+
categoryModel,
|
|
125059
|
+
fallbackState: undefined
|
|
124844
125060
|
};
|
|
124845
125061
|
}
|
|
124846
125062
|
const fallbackState = {
|
|
@@ -124856,7 +125072,8 @@ async function retrySyncPromptWithFallbacks(input) {
|
|
|
124856
125072
|
if (!nextFallback) {
|
|
124857
125073
|
return {
|
|
124858
125074
|
promptError: finalError,
|
|
124859
|
-
categoryModel
|
|
125075
|
+
categoryModel,
|
|
125076
|
+
fallbackState
|
|
124860
125077
|
};
|
|
124861
125078
|
}
|
|
124862
125079
|
const fallbackModel = toDelegatedModelConfig(nextFallback);
|
|
@@ -124864,7 +125081,8 @@ async function retrySyncPromptWithFallbacks(input) {
|
|
|
124864
125081
|
if (!promptError) {
|
|
124865
125082
|
return {
|
|
124866
125083
|
promptError: null,
|
|
124867
|
-
categoryModel: fallbackModel
|
|
125084
|
+
categoryModel: fallbackModel,
|
|
125085
|
+
fallbackState
|
|
124868
125086
|
};
|
|
124869
125087
|
}
|
|
124870
125088
|
finalError = promptError;
|
|
@@ -124873,6 +125091,12 @@ async function retrySyncPromptWithFallbacks(input) {
|
|
|
124873
125091
|
fallbackState.pending = true;
|
|
124874
125092
|
}
|
|
124875
125093
|
}
|
|
125094
|
+
function getNextSyncFallbackModel(sessionID, fallbackState) {
|
|
125095
|
+
if (!fallbackState)
|
|
125096
|
+
return null;
|
|
125097
|
+
const nextFallback = getNextReachableFallback(sessionID, fallbackState);
|
|
125098
|
+
return nextFallback ? toDelegatedModelConfig(nextFallback) : null;
|
|
125099
|
+
}
|
|
124876
125100
|
|
|
124877
125101
|
// src/tools/delegate-task/sync-task.ts
|
|
124878
125102
|
async function executeSyncTask(args, ctx, executorCtx, parentContext, agentToUse, categoryModel, systemContent, modelInfo, fallbackChain, deps = syncTaskDeps) {
|
|
@@ -124911,26 +125135,50 @@ async function executeSyncTask(args, ctx, executorCtx, parentContext, agentToUse
|
|
|
124911
125135
|
const sessionID = createSessionResult.sessionID;
|
|
124912
125136
|
spawnReservation?.commit();
|
|
124913
125137
|
syncSessionID = sessionID;
|
|
124914
|
-
|
|
124915
|
-
|
|
124916
|
-
|
|
124917
|
-
|
|
124918
|
-
|
|
124919
|
-
|
|
124920
|
-
|
|
124921
|
-
|
|
124922
|
-
|
|
124923
|
-
|
|
124924
|
-
|
|
124925
|
-
|
|
124926
|
-
|
|
124927
|
-
|
|
124928
|
-
|
|
124929
|
-
|
|
124930
|
-
|
|
125138
|
+
const registerSyncSession = async (newSessionID) => {
|
|
125139
|
+
syncSessionID = newSessionID;
|
|
125140
|
+
subagentSessions.add(newSessionID);
|
|
125141
|
+
syncSubagentSessions.add(newSessionID);
|
|
125142
|
+
setSessionAgent(newSessionID, agentToUse);
|
|
125143
|
+
executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(newSessionID, fallbackChain);
|
|
125144
|
+
if (args.category) {
|
|
125145
|
+
SessionCategoryRegistry.register(newSessionID, args.category);
|
|
125146
|
+
}
|
|
125147
|
+
if (onSyncSessionCreated) {
|
|
125148
|
+
log("[task] Invoking onSyncSessionCreated callback", { sessionID: newSessionID, parentID: parentContext.sessionID });
|
|
125149
|
+
try {
|
|
125150
|
+
await onSyncSessionCreated({
|
|
125151
|
+
sessionID: newSessionID,
|
|
125152
|
+
parentID: parentContext.sessionID,
|
|
125153
|
+
title: args.description
|
|
125154
|
+
});
|
|
125155
|
+
} catch (error92) {
|
|
125156
|
+
log("[task] onSyncSessionCreated callback failed", { error: String(error92) });
|
|
125157
|
+
}
|
|
125158
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
124931
125159
|
}
|
|
124932
|
-
|
|
124933
|
-
|
|
125160
|
+
};
|
|
125161
|
+
const publishSyncMetadata = async (currentSessionID, currentModel, currentTaskId, spawnDepth) => {
|
|
125162
|
+
await publishToolMetadata(ctx, {
|
|
125163
|
+
title: args.description,
|
|
125164
|
+
metadata: {
|
|
125165
|
+
prompt: args.prompt,
|
|
125166
|
+
agent: agentToUse,
|
|
125167
|
+
category: args.category,
|
|
125168
|
+
...args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {},
|
|
125169
|
+
load_skills: args.load_skills,
|
|
125170
|
+
description: args.description,
|
|
125171
|
+
run_in_background: args.run_in_background,
|
|
125172
|
+
taskId: currentSessionID,
|
|
125173
|
+
sessionId: currentSessionID,
|
|
125174
|
+
sync: true,
|
|
125175
|
+
spawnDepth,
|
|
125176
|
+
command: args.command,
|
|
125177
|
+
model: resolveMetadataModel(currentModel, parentContext.model)
|
|
125178
|
+
}
|
|
125179
|
+
});
|
|
125180
|
+
};
|
|
125181
|
+
await registerSyncSession(sessionID);
|
|
124934
125182
|
taskId = `sync_${sessionID.slice(0, 8)}`;
|
|
124935
125183
|
const startTime = new Date;
|
|
124936
125184
|
if (toastManager) {
|
|
@@ -124945,25 +125193,7 @@ async function executeSyncTask(args, ctx, executorCtx, parentContext, agentToUse
|
|
|
124945
125193
|
modelInfo
|
|
124946
125194
|
});
|
|
124947
125195
|
}
|
|
124948
|
-
|
|
124949
|
-
title: args.description,
|
|
124950
|
-
metadata: {
|
|
124951
|
-
prompt: args.prompt,
|
|
124952
|
-
agent: agentToUse,
|
|
124953
|
-
category: args.category,
|
|
124954
|
-
...args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {},
|
|
124955
|
-
load_skills: args.load_skills,
|
|
124956
|
-
description: args.description,
|
|
124957
|
-
run_in_background: args.run_in_background,
|
|
124958
|
-
taskId: sessionID,
|
|
124959
|
-
sessionId: sessionID,
|
|
124960
|
-
sync: true,
|
|
124961
|
-
spawnDepth: spawnContext.childDepth,
|
|
124962
|
-
command: args.command,
|
|
124963
|
-
model: resolveMetadataModel(categoryModel, parentContext.model)
|
|
124964
|
-
}
|
|
124965
|
-
};
|
|
124966
|
-
await publishToolMetadata(ctx, syncTaskMeta);
|
|
125196
|
+
await publishSyncMetadata(sessionID, categoryModel, taskId, spawnContext.childDepth);
|
|
124967
125197
|
const syncPromptInput = {
|
|
124968
125198
|
sessionID,
|
|
124969
125199
|
agentToUse,
|
|
@@ -124974,55 +125204,106 @@ async function executeSyncTask(args, ctx, executorCtx, parentContext, agentToUse
|
|
|
124974
125204
|
sisyphusAgentConfig: executorCtx.sisyphusAgentConfig
|
|
124975
125205
|
};
|
|
124976
125206
|
let effectiveCategoryModel = categoryModel;
|
|
124977
|
-
let
|
|
124978
|
-
|
|
124979
|
-
|
|
124980
|
-
|
|
124981
|
-
|
|
124982
|
-
|
|
124983
|
-
|
|
124984
|
-
|
|
124985
|
-
|
|
124986
|
-
|
|
124987
|
-
|
|
124988
|
-
|
|
124989
|
-
|
|
124990
|
-
|
|
125207
|
+
let fallbackState = effectiveCategoryModel && fallbackChain?.length ? {
|
|
125208
|
+
providerID: effectiveCategoryModel.providerID,
|
|
125209
|
+
modelID: effectiveCategoryModel.modelID,
|
|
125210
|
+
fallbackChain,
|
|
125211
|
+
attemptCount: 0,
|
|
125212
|
+
pending: true
|
|
125213
|
+
} : undefined;
|
|
125214
|
+
let activeSessionID = sessionID;
|
|
125215
|
+
const cleanupRetrySession = (currentSessionID) => {
|
|
125216
|
+
subagentSessions.delete(currentSessionID);
|
|
125217
|
+
syncSubagentSessions.delete(currentSessionID);
|
|
125218
|
+
executorCtx.modelFallbackControllerAccessor?.clearSessionFallbackChain(currentSessionID);
|
|
125219
|
+
SessionCategoryRegistry.remove(currentSessionID);
|
|
125220
|
+
};
|
|
125221
|
+
try {
|
|
125222
|
+
while (true) {
|
|
125223
|
+
let promptError = await deps.sendSyncPrompt(client2, {
|
|
125224
|
+
...syncPromptInput,
|
|
125225
|
+
sessionID: activeSessionID,
|
|
125226
|
+
categoryModel: effectiveCategoryModel
|
|
125227
|
+
});
|
|
125228
|
+
if (promptError) {
|
|
125229
|
+
const promptResult = await retrySyncPromptWithFallbacks({
|
|
125230
|
+
sessionID: activeSessionID,
|
|
125231
|
+
initialError: promptError,
|
|
125232
|
+
categoryModel: effectiveCategoryModel,
|
|
125233
|
+
fallbackChain,
|
|
125234
|
+
sendPrompt: async (fallbackModel) => {
|
|
125235
|
+
return deps.sendSyncPrompt(client2, {
|
|
125236
|
+
...syncPromptInput,
|
|
125237
|
+
sessionID: activeSessionID,
|
|
125238
|
+
categoryModel: fallbackModel
|
|
125239
|
+
});
|
|
125240
|
+
}
|
|
124991
125241
|
});
|
|
125242
|
+
promptError = promptResult.promptError;
|
|
125243
|
+
effectiveCategoryModel = promptResult.categoryModel;
|
|
125244
|
+
fallbackState = promptResult.fallbackState ?? fallbackState;
|
|
125245
|
+
if (promptError) {
|
|
125246
|
+
return promptError;
|
|
125247
|
+
}
|
|
124992
125248
|
}
|
|
124993
|
-
|
|
124994
|
-
|
|
124995
|
-
|
|
124996
|
-
|
|
124997
|
-
|
|
124998
|
-
|
|
124999
|
-
|
|
125000
|
-
|
|
125001
|
-
|
|
125002
|
-
|
|
125003
|
-
|
|
125004
|
-
|
|
125005
|
-
|
|
125006
|
-
|
|
125007
|
-
|
|
125008
|
-
|
|
125009
|
-
|
|
125010
|
-
|
|
125011
|
-
|
|
125012
|
-
|
|
125013
|
-
|
|
125014
|
-
|
|
125015
|
-
|
|
125016
|
-
|
|
125017
|
-
|
|
125018
|
-
|
|
125019
|
-
|
|
125249
|
+
const pollError = await deps.pollSyncSession(ctx, client2, {
|
|
125250
|
+
sessionID: activeSessionID,
|
|
125251
|
+
agentToUse,
|
|
125252
|
+
toastManager,
|
|
125253
|
+
taskId
|
|
125254
|
+
}, syncPollTimeoutMs);
|
|
125255
|
+
if (pollError) {
|
|
125256
|
+
const nextFallbackModel = shouldRetryError({ message: pollError }) ? getNextSyncFallbackModel(activeSessionID, fallbackState) : null;
|
|
125257
|
+
if (!nextFallbackModel) {
|
|
125258
|
+
return pollError;
|
|
125259
|
+
}
|
|
125260
|
+
cleanupRetrySession(activeSessionID);
|
|
125261
|
+
const retrySessionResult = await deps.createSyncSession(client2, {
|
|
125262
|
+
parentSessionID: parentContext.sessionID,
|
|
125263
|
+
agentToUse,
|
|
125264
|
+
description: args.description,
|
|
125265
|
+
defaultDirectory: directory
|
|
125266
|
+
});
|
|
125267
|
+
if (!retrySessionResult.ok) {
|
|
125268
|
+
return retrySessionResult.error;
|
|
125269
|
+
}
|
|
125270
|
+
activeSessionID = retrySessionResult.sessionID;
|
|
125271
|
+
effectiveCategoryModel = nextFallbackModel;
|
|
125272
|
+
await registerSyncSession(activeSessionID);
|
|
125273
|
+
if (toastManager && taskId) {
|
|
125274
|
+
toastManager.addTask({
|
|
125275
|
+
id: taskId,
|
|
125276
|
+
sessionID: activeSessionID,
|
|
125277
|
+
description: args.description,
|
|
125278
|
+
agent: agentToUse,
|
|
125279
|
+
isBackground: false,
|
|
125280
|
+
category: args.category,
|
|
125281
|
+
skills: args.load_skills,
|
|
125282
|
+
modelInfo
|
|
125283
|
+
});
|
|
125284
|
+
}
|
|
125285
|
+
if (taskId) {
|
|
125286
|
+
await publishSyncMetadata(activeSessionID, effectiveCategoryModel, taskId, spawnContext.childDepth);
|
|
125287
|
+
}
|
|
125288
|
+
continue;
|
|
125289
|
+
}
|
|
125290
|
+
const result = await deps.fetchSyncResult(client2, activeSessionID);
|
|
125291
|
+
if (!result.ok) {
|
|
125292
|
+
return result.error;
|
|
125293
|
+
}
|
|
125294
|
+
const duration5 = formatDuration2(startTime);
|
|
125295
|
+
const actualModelStr = effectiveCategoryModel ? `${effectiveCategoryModel.providerID}/${effectiveCategoryModel.modelID}` : undefined;
|
|
125296
|
+
const parentModelStr = parentContext.model ? `${parentContext.model.providerID}/${parentContext.model.modelID}` : undefined;
|
|
125297
|
+
let modelRoutingNote = "";
|
|
125298
|
+
if (actualModelStr && parentModelStr && actualModelStr !== parentModelStr) {
|
|
125299
|
+
modelRoutingNote = `
|
|
125020
125300
|
\u26A0\uFE0F Model routing: parent used ${parentModelStr}, this subagent used ${actualModelStr} (via category: ${args.category ?? "unknown"})`;
|
|
125021
|
-
|
|
125022
|
-
|
|
125301
|
+
} else if (actualModelStr) {
|
|
125302
|
+
modelRoutingNote = `
|
|
125023
125303
|
Model: ${actualModelStr}${args.category ? ` (category: ${args.category})` : ""}`;
|
|
125024
|
-
|
|
125025
|
-
|
|
125304
|
+
}
|
|
125305
|
+
await publishSyncMetadata(activeSessionID, effectiveCategoryModel, taskId, spawnContext.childDepth);
|
|
125306
|
+
return `Task completed in ${duration5}.
|
|
125026
125307
|
|
|
125027
125308
|
Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""}${modelRoutingNote}
|
|
125028
125309
|
|
|
@@ -125031,11 +125312,12 @@ Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""}${mod
|
|
|
125031
125312
|
${result.textContent || "(No text output)"}
|
|
125032
125313
|
|
|
125033
125314
|
${buildTaskMetadataBlock({
|
|
125034
|
-
|
|
125035
|
-
|
|
125036
|
-
|
|
125037
|
-
|
|
125038
|
-
|
|
125315
|
+
sessionId: activeSessionID,
|
|
125316
|
+
taskId: activeSessionID,
|
|
125317
|
+
agent: agentToUse,
|
|
125318
|
+
category: args.category
|
|
125319
|
+
})}`;
|
|
125320
|
+
}
|
|
125039
125321
|
} finally {
|
|
125040
125322
|
if (toastManager && taskId !== undefined) {
|
|
125041
125323
|
toastManager.removeTask(taskId);
|
|
@@ -125114,6 +125396,7 @@ function resolveCategoryConfig(categoryName, options) {
|
|
|
125114
125396
|
}
|
|
125115
125397
|
|
|
125116
125398
|
// src/tools/delegate-task/category-resolver.ts
|
|
125399
|
+
init_constants2();
|
|
125117
125400
|
init_plugin_identity();
|
|
125118
125401
|
|
|
125119
125402
|
// src/tools/delegate-task/available-models.ts
|
|
@@ -125338,6 +125621,19 @@ function applyCategoryParams(base, config4) {
|
|
|
125338
125621
|
result.thinking = config4.thinking;
|
|
125339
125622
|
return result;
|
|
125340
125623
|
}
|
|
125624
|
+
function resolveCategoryPromptAppendForModel(categoryName, actualModel, staticPromptAppend, userPromptAppend) {
|
|
125625
|
+
const dynamicResolver = CATEGORY_PROMPT_APPEND_RESOLVERS[categoryName];
|
|
125626
|
+
if (!dynamicResolver) {
|
|
125627
|
+
return staticPromptAppend || undefined;
|
|
125628
|
+
}
|
|
125629
|
+
const dynamicBase = dynamicResolver(actualModel);
|
|
125630
|
+
if (!userPromptAppend) {
|
|
125631
|
+
return dynamicBase || undefined;
|
|
125632
|
+
}
|
|
125633
|
+
return dynamicBase ? `${dynamicBase}
|
|
125634
|
+
|
|
125635
|
+
${userPromptAppend}` : userPromptAppend;
|
|
125636
|
+
}
|
|
125341
125637
|
async function resolveCategoryExecution(args, executorCtx, inheritedModel, systemDefaultModel) {
|
|
125342
125638
|
const { client: client2, userCategories, sisyphusJuniorModel } = executorCtx;
|
|
125343
125639
|
const categoryName = args.category;
|
|
@@ -125467,7 +125763,7 @@ Available categories: ${allCategoryNames}`
|
|
|
125467
125763
|
const parsedModel = parseModelString(actualModel);
|
|
125468
125764
|
categoryModel = parsedModel ?? undefined;
|
|
125469
125765
|
}
|
|
125470
|
-
const categoryPromptAppend = resolved.promptAppend
|
|
125766
|
+
const categoryPromptAppend = resolveCategoryPromptAppendForModel(args.category, actualModel, resolved.promptAppend, userCategories?.[args.category]?.prompt_append);
|
|
125471
125767
|
if (!categoryModel && !actualModel && !isModelResolutionSkipped) {
|
|
125472
125768
|
const categoryNames = Object.keys(enabledCategories);
|
|
125473
125769
|
return {
|
|
@@ -129174,6 +129470,43 @@ function formatDuration3(start, end) {
|
|
|
129174
129470
|
}
|
|
129175
129471
|
|
|
129176
129472
|
// src/features/background-agent/background-task-notification-template.ts
|
|
129473
|
+
function formatAttemptModel(attempt) {
|
|
129474
|
+
if (attempt.providerID && attempt.modelID) {
|
|
129475
|
+
return `${attempt.providerID}/${attempt.modelID}`;
|
|
129476
|
+
}
|
|
129477
|
+
if (attempt.modelID) {
|
|
129478
|
+
return attempt.modelID;
|
|
129479
|
+
}
|
|
129480
|
+
if (attempt.providerID) {
|
|
129481
|
+
return attempt.providerID;
|
|
129482
|
+
}
|
|
129483
|
+
return "unknown-model";
|
|
129484
|
+
}
|
|
129485
|
+
function formatAttemptTimeline(task) {
|
|
129486
|
+
if (!task.attempts || task.attempts.length <= 1) {
|
|
129487
|
+
return "";
|
|
129488
|
+
}
|
|
129489
|
+
const lines = task.attempts.map((attempt) => {
|
|
129490
|
+
const attemptLines = [
|
|
129491
|
+
` - Attempt ${attempt.attemptNumber} \u2014 ${attempt.status.toUpperCase()} \u2014 ${formatAttemptModel(attempt)} \u2014 ${attempt.sessionID ?? "unknown"}`
|
|
129492
|
+
];
|
|
129493
|
+
if (attempt.status !== "completed" && attempt.error) {
|
|
129494
|
+
attemptLines.push(` Error: ${attempt.error}`);
|
|
129495
|
+
}
|
|
129496
|
+
return attemptLines.join(`
|
|
129497
|
+
`);
|
|
129498
|
+
}).join(`
|
|
129499
|
+
`);
|
|
129500
|
+
return `Background task attempts:
|
|
129501
|
+
${lines}`;
|
|
129502
|
+
}
|
|
129503
|
+
function formatTaskSummaryLine(task) {
|
|
129504
|
+
const baseLine = `- \`${task.id}\`: ${task.description || task.id}`;
|
|
129505
|
+
const statusSuffix = task.status === "completed" ? "" : ` [${task.status.toUpperCase()}]${task.error ? ` - ${task.error}` : ""}`;
|
|
129506
|
+
const timeline = formatAttemptTimeline(task);
|
|
129507
|
+
return `${baseLine}${statusSuffix}${timeline ? `
|
|
129508
|
+
${timeline}` : ""}`;
|
|
129509
|
+
}
|
|
129177
129510
|
function buildBackgroundTaskNotificationText(input) {
|
|
129178
129511
|
const { task, duration: duration5, statusText, allComplete, remainingCount, completedTasks } = input;
|
|
129179
129512
|
const safeDescription = (t) => t.description || t.id;
|
|
@@ -129182,9 +129515,9 @@ function buildBackgroundTaskNotificationText(input) {
|
|
|
129182
129515
|
if (allComplete) {
|
|
129183
129516
|
const succeededTasks = completedTasks.filter((t) => t.status === "completed");
|
|
129184
129517
|
const failedTasks = completedTasks.filter((t) => t.status !== "completed");
|
|
129185
|
-
const succeededText = succeededTasks.length > 0 ? succeededTasks.map((t) =>
|
|
129518
|
+
const succeededText = succeededTasks.length > 0 ? succeededTasks.map((t) => formatTaskSummaryLine(t)).join(`
|
|
129186
129519
|
`) : "";
|
|
129187
|
-
const failedText = failedTasks.length > 0 ? failedTasks.map((t) =>
|
|
129520
|
+
const failedText = failedTasks.length > 0 ? failedTasks.map((t) => formatTaskSummaryLine(t)).join(`
|
|
129188
129521
|
`) : "";
|
|
129189
129522
|
const hasFailures = failedTasks.length > 0;
|
|
129190
129523
|
const header = hasFailures ? `[ALL BACKGROUND TASKS FINISHED - ${failedTasks.length} FAILED]` : "[ALL BACKGROUND TASKS COMPLETE]";
|
|
@@ -129201,7 +129534,7 @@ ${failedText}
|
|
|
129201
129534
|
`;
|
|
129202
129535
|
}
|
|
129203
129536
|
if (!body) {
|
|
129204
|
-
body =
|
|
129537
|
+
body = `${formatTaskSummaryLine(task)}
|
|
129205
129538
|
`;
|
|
129206
129539
|
}
|
|
129207
129540
|
return `<system-reminder>
|
|
@@ -129228,83 +129561,6 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
|
|
|
129228
129561
|
</system-reminder>`;
|
|
129229
129562
|
}
|
|
129230
129563
|
|
|
129231
|
-
// src/features/background-agent/error-classifier.ts
|
|
129232
|
-
function isRecord15(value) {
|
|
129233
|
-
return typeof value === "object" && value !== null;
|
|
129234
|
-
}
|
|
129235
|
-
function isAbortedSessionError(error92) {
|
|
129236
|
-
const message = getErrorText(error92);
|
|
129237
|
-
return message.toLowerCase().includes("aborted");
|
|
129238
|
-
}
|
|
129239
|
-
function getErrorText(error92) {
|
|
129240
|
-
if (!error92)
|
|
129241
|
-
return "";
|
|
129242
|
-
if (typeof error92 === "string")
|
|
129243
|
-
return error92;
|
|
129244
|
-
if (error92 instanceof Error) {
|
|
129245
|
-
return `${error92.name}: ${error92.message}`;
|
|
129246
|
-
}
|
|
129247
|
-
if (typeof error92 === "object" && error92 !== null) {
|
|
129248
|
-
if ("message" in error92 && typeof error92.message === "string") {
|
|
129249
|
-
return error92.message;
|
|
129250
|
-
}
|
|
129251
|
-
if ("name" in error92 && typeof error92.name === "string") {
|
|
129252
|
-
return error92.name;
|
|
129253
|
-
}
|
|
129254
|
-
}
|
|
129255
|
-
return "";
|
|
129256
|
-
}
|
|
129257
|
-
function extractErrorName2(error92) {
|
|
129258
|
-
if (isRecord15(error92) && typeof error92["name"] === "string")
|
|
129259
|
-
return error92["name"];
|
|
129260
|
-
if (error92 instanceof Error)
|
|
129261
|
-
return error92.name;
|
|
129262
|
-
return;
|
|
129263
|
-
}
|
|
129264
|
-
function extractErrorMessage(error92) {
|
|
129265
|
-
if (!error92)
|
|
129266
|
-
return;
|
|
129267
|
-
if (typeof error92 === "string")
|
|
129268
|
-
return error92;
|
|
129269
|
-
if (error92 instanceof Error)
|
|
129270
|
-
return error92.message;
|
|
129271
|
-
if (isRecord15(error92)) {
|
|
129272
|
-
const dataRaw = error92["data"];
|
|
129273
|
-
const candidates = [
|
|
129274
|
-
error92,
|
|
129275
|
-
dataRaw,
|
|
129276
|
-
error92["error"],
|
|
129277
|
-
isRecord15(dataRaw) ? dataRaw["error"] : undefined,
|
|
129278
|
-
error92["cause"]
|
|
129279
|
-
];
|
|
129280
|
-
for (const candidate of candidates) {
|
|
129281
|
-
if (typeof candidate === "string" && candidate.length > 0)
|
|
129282
|
-
return candidate;
|
|
129283
|
-
if (isRecord15(candidate) && typeof candidate["message"] === "string" && candidate["message"].length > 0) {
|
|
129284
|
-
return candidate["message"];
|
|
129285
|
-
}
|
|
129286
|
-
}
|
|
129287
|
-
}
|
|
129288
|
-
try {
|
|
129289
|
-
return JSON.stringify(error92);
|
|
129290
|
-
} catch {
|
|
129291
|
-
return String(error92);
|
|
129292
|
-
}
|
|
129293
|
-
}
|
|
129294
|
-
function getSessionErrorMessage(properties) {
|
|
129295
|
-
const errorRaw = properties["error"];
|
|
129296
|
-
if (!isRecord15(errorRaw))
|
|
129297
|
-
return;
|
|
129298
|
-
const dataRaw = errorRaw["data"];
|
|
129299
|
-
if (isRecord15(dataRaw)) {
|
|
129300
|
-
const message2 = dataRaw["message"];
|
|
129301
|
-
if (typeof message2 === "string")
|
|
129302
|
-
return message2;
|
|
129303
|
-
}
|
|
129304
|
-
const message = errorRaw["message"];
|
|
129305
|
-
return typeof message === "string" ? message : undefined;
|
|
129306
|
-
}
|
|
129307
|
-
|
|
129308
129564
|
// src/features/background-agent/abort-with-timeout.ts
|
|
129309
129565
|
async function abortWithTimeout(client2, sessionID, timeoutMs = 1e4) {
|
|
129310
129566
|
let timeoutHandle;
|
|
@@ -129332,9 +129588,138 @@ async function abortWithTimeout(client2, sessionID, timeoutMs = 1e4) {
|
|
|
129332
129588
|
}
|
|
129333
129589
|
}
|
|
129334
129590
|
|
|
129591
|
+
// src/features/background-agent/attempt-lifecycle.ts
|
|
129592
|
+
function toAttemptModel(model) {
|
|
129593
|
+
return {
|
|
129594
|
+
providerID: model?.providerID,
|
|
129595
|
+
modelID: model?.modelID,
|
|
129596
|
+
variant: model?.variant
|
|
129597
|
+
};
|
|
129598
|
+
}
|
|
129599
|
+
function toTaskModel(attempt) {
|
|
129600
|
+
if (!attempt.providerID || !attempt.modelID) {
|
|
129601
|
+
return;
|
|
129602
|
+
}
|
|
129603
|
+
return {
|
|
129604
|
+
providerID: attempt.providerID,
|
|
129605
|
+
modelID: attempt.modelID,
|
|
129606
|
+
...attempt.variant ? { variant: attempt.variant } : {}
|
|
129607
|
+
};
|
|
129608
|
+
}
|
|
129609
|
+
function getAttemptIndex(task, attemptID) {
|
|
129610
|
+
return task.attempts?.findIndex((attempt) => attempt.attemptID === attemptID) ?? -1;
|
|
129611
|
+
}
|
|
129612
|
+
function getAttempt(task, attemptID) {
|
|
129613
|
+
const index = getAttemptIndex(task, attemptID);
|
|
129614
|
+
return index === -1 ? undefined : task.attempts?.[index];
|
|
129615
|
+
}
|
|
129616
|
+
function isTerminalStatus(status) {
|
|
129617
|
+
return status === "completed" || status === "error" || status === "cancelled" || status === "interrupt";
|
|
129618
|
+
}
|
|
129619
|
+
function getCurrentAttempt(task) {
|
|
129620
|
+
if (!task.currentAttemptID) {
|
|
129621
|
+
return;
|
|
129622
|
+
}
|
|
129623
|
+
return getAttempt(task, task.currentAttemptID);
|
|
129624
|
+
}
|
|
129625
|
+
function ensureCurrentAttempt(task, model = task.model) {
|
|
129626
|
+
const existingAttempt = getCurrentAttempt(task);
|
|
129627
|
+
if (existingAttempt) {
|
|
129628
|
+
return existingAttempt;
|
|
129629
|
+
}
|
|
129630
|
+
const attempt = {
|
|
129631
|
+
attemptID: `att_${crypto.randomUUID().slice(0, 8)}`,
|
|
129632
|
+
attemptNumber: (task.attempts?.length ?? 0) + 1,
|
|
129633
|
+
sessionID: task.sessionID,
|
|
129634
|
+
...toAttemptModel(model),
|
|
129635
|
+
status: task.status,
|
|
129636
|
+
error: task.error,
|
|
129637
|
+
startedAt: task.startedAt,
|
|
129638
|
+
completedAt: task.completedAt
|
|
129639
|
+
};
|
|
129640
|
+
task.attempts = [...task.attempts ?? [], attempt];
|
|
129641
|
+
task.currentAttemptID = attempt.attemptID;
|
|
129642
|
+
return attempt;
|
|
129643
|
+
}
|
|
129644
|
+
function projectTaskFromCurrentAttempt(task) {
|
|
129645
|
+
const currentAttempt = getCurrentAttempt(task);
|
|
129646
|
+
if (!currentAttempt) {
|
|
129647
|
+
return task;
|
|
129648
|
+
}
|
|
129649
|
+
task.status = currentAttempt.status;
|
|
129650
|
+
task.sessionID = currentAttempt.sessionID;
|
|
129651
|
+
task.startedAt = currentAttempt.startedAt;
|
|
129652
|
+
task.completedAt = currentAttempt.completedAt;
|
|
129653
|
+
task.error = currentAttempt.error;
|
|
129654
|
+
task.model = toTaskModel(currentAttempt);
|
|
129655
|
+
return task;
|
|
129656
|
+
}
|
|
129657
|
+
function startAttempt(task, model) {
|
|
129658
|
+
const attempt = {
|
|
129659
|
+
attemptID: `att_${crypto.randomUUID().slice(0, 8)}`,
|
|
129660
|
+
attemptNumber: (task.attempts?.length ?? 0) + 1,
|
|
129661
|
+
...toAttemptModel(model),
|
|
129662
|
+
status: "pending"
|
|
129663
|
+
};
|
|
129664
|
+
task.attempts = [...task.attempts ?? [], attempt];
|
|
129665
|
+
task.currentAttemptID = attempt.attemptID;
|
|
129666
|
+
task.status = "pending";
|
|
129667
|
+
task.sessionID = undefined;
|
|
129668
|
+
task.startedAt = undefined;
|
|
129669
|
+
task.completedAt = undefined;
|
|
129670
|
+
task.error = undefined;
|
|
129671
|
+
task.model = model;
|
|
129672
|
+
return attempt;
|
|
129673
|
+
}
|
|
129674
|
+
function bindAttemptSession(task, attemptID, sessionID, model) {
|
|
129675
|
+
ensureCurrentAttempt(task, model);
|
|
129676
|
+
if (task.currentAttemptID !== attemptID) {
|
|
129677
|
+
return;
|
|
129678
|
+
}
|
|
129679
|
+
const attempt = getAttempt(task, attemptID);
|
|
129680
|
+
if (!attempt || isTerminalStatus(attempt.status)) {
|
|
129681
|
+
return;
|
|
129682
|
+
}
|
|
129683
|
+
attempt.sessionID = sessionID;
|
|
129684
|
+
attempt.status = "running";
|
|
129685
|
+
attempt.startedAt = new Date;
|
|
129686
|
+
attempt.completedAt = undefined;
|
|
129687
|
+
attempt.error = undefined;
|
|
129688
|
+
attempt.providerID = model?.providerID ?? attempt.providerID;
|
|
129689
|
+
attempt.modelID = model?.modelID ?? attempt.modelID;
|
|
129690
|
+
attempt.variant = model?.variant ?? attempt.variant;
|
|
129691
|
+
return getCurrentAttempt(projectTaskFromCurrentAttempt(task));
|
|
129692
|
+
}
|
|
129693
|
+
function finalizeAttempt(task, attemptID, status, error92) {
|
|
129694
|
+
const attempt = getAttempt(task, attemptID);
|
|
129695
|
+
if (!attempt) {
|
|
129696
|
+
return;
|
|
129697
|
+
}
|
|
129698
|
+
attempt.status = status;
|
|
129699
|
+
attempt.completedAt = new Date;
|
|
129700
|
+
attempt.error = error92;
|
|
129701
|
+
if (task.currentAttemptID === attemptID) {
|
|
129702
|
+
projectTaskFromCurrentAttempt(task);
|
|
129703
|
+
}
|
|
129704
|
+
return attempt;
|
|
129705
|
+
}
|
|
129706
|
+
function scheduleRetryAttempt(task, failedAttemptID, nextModel, error92) {
|
|
129707
|
+
const failedAttempt = finalizeAttempt(task, failedAttemptID, "error", error92);
|
|
129708
|
+
if (!failedAttempt || task.currentAttemptID !== failedAttemptID) {
|
|
129709
|
+
return;
|
|
129710
|
+
}
|
|
129711
|
+
return startAttempt(task, nextModel);
|
|
129712
|
+
}
|
|
129713
|
+
function findAttemptBySession(task, sessionID) {
|
|
129714
|
+
return task.attempts?.find((attempt) => attempt.sessionID === sessionID);
|
|
129715
|
+
}
|
|
129716
|
+
|
|
129335
129717
|
// src/features/background-agent/fallback-retry-handler.ts
|
|
129718
|
+
function canonicalizeModelID2(modelID) {
|
|
129719
|
+
return modelID.toLowerCase().replace(/\./g, "-");
|
|
129720
|
+
}
|
|
129336
129721
|
async function tryFallbackRetry(args) {
|
|
129337
|
-
const { task, errorInfo, source, concurrencyManager, client: client2, idleDeferralTimers, queuesByKey, processKey } = args;
|
|
129722
|
+
const { task, errorInfo, source, concurrencyManager, client: client2, idleDeferralTimers, queuesByKey, processKey, onRetrying } = args;
|
|
129338
129723
|
const fallbackChain = task.fallbackChain;
|
|
129339
129724
|
const canRetry = shouldRetryError(errorInfo) && fallbackChain && fallbackChain.length > 0 && hasMoreFallbacks(fallbackChain, task.attemptCount ?? 0);
|
|
129340
129725
|
if (!canRetry)
|
|
@@ -129354,6 +129739,7 @@ async function tryFallbackRetry(args) {
|
|
|
129354
129739
|
};
|
|
129355
129740
|
let selectedAttemptCount = attemptCount;
|
|
129356
129741
|
let nextFallback;
|
|
129742
|
+
let nextProviderID;
|
|
129357
129743
|
while (fallbackChain && selectedAttemptCount < fallbackChain.length) {
|
|
129358
129744
|
const candidate = getNextFallback(fallbackChain, selectedAttemptCount);
|
|
129359
129745
|
if (!candidate)
|
|
@@ -129368,12 +129754,25 @@ async function tryFallbackRetry(args) {
|
|
|
129368
129754
|
});
|
|
129369
129755
|
continue;
|
|
129370
129756
|
}
|
|
129757
|
+
const candidateProviderID = selectFallbackProvider(candidate.providers, task.model?.providerID);
|
|
129758
|
+
const candidateModelID = transformModelForProvider(candidateProviderID, candidate.model);
|
|
129759
|
+
const isNoOpFallback = !!task.model && candidateProviderID.toLowerCase() === task.model.providerID.toLowerCase() && canonicalizeModelID2(candidateModelID) === canonicalizeModelID2(task.model.modelID);
|
|
129760
|
+
if (isNoOpFallback) {
|
|
129761
|
+
log("[background-agent] Skipping no-op fallback:", {
|
|
129762
|
+
taskId: task.id,
|
|
129763
|
+
source,
|
|
129764
|
+
model: candidate.model,
|
|
129765
|
+
providers: candidate.providers
|
|
129766
|
+
});
|
|
129767
|
+
continue;
|
|
129768
|
+
}
|
|
129371
129769
|
nextFallback = candidate;
|
|
129770
|
+
nextProviderID = candidateProviderID;
|
|
129372
129771
|
break;
|
|
129373
129772
|
}
|
|
129374
129773
|
if (!nextFallback)
|
|
129375
129774
|
return false;
|
|
129376
|
-
const providerID = selectFallbackProvider(nextFallback.providers, task.model?.providerID);
|
|
129775
|
+
const providerID = nextProviderID ?? selectFallbackProvider(nextFallback.providers, task.model?.providerID);
|
|
129377
129776
|
log("[background-agent] Retryable error, attempting fallback:", {
|
|
129378
129777
|
taskId: task.id,
|
|
129379
129778
|
source,
|
|
@@ -129392,18 +129791,34 @@ async function tryFallbackRetry(args) {
|
|
|
129392
129791
|
idleDeferralTimers.delete(task.id);
|
|
129393
129792
|
}
|
|
129394
129793
|
const previousSessionID = task.sessionID;
|
|
129395
|
-
|
|
129794
|
+
const previousModel = task.model;
|
|
129396
129795
|
const transformedModelId = transformModelForProvider(providerID, nextFallback.model);
|
|
129397
|
-
|
|
129796
|
+
const nextModel = {
|
|
129398
129797
|
providerID,
|
|
129399
129798
|
modelID: transformedModelId,
|
|
129400
129799
|
variant: nextFallback.variant
|
|
129401
129800
|
};
|
|
129402
|
-
task.
|
|
129403
|
-
|
|
129404
|
-
task.
|
|
129801
|
+
task.attemptCount = selectedAttemptCount;
|
|
129802
|
+
const failedAttemptID = ensureCurrentAttempt(task, previousModel).attemptID;
|
|
129803
|
+
const nextAttempt = failedAttemptID ? scheduleRetryAttempt(task, failedAttemptID, nextModel, errorInfo.message) : undefined;
|
|
129804
|
+
if (!nextAttempt) {
|
|
129805
|
+
return false;
|
|
129806
|
+
}
|
|
129405
129807
|
task.queuedAt = new Date;
|
|
129406
|
-
task.
|
|
129808
|
+
task.retryNotification = {
|
|
129809
|
+
previousSessionID,
|
|
129810
|
+
failedModel: previousModel ? `${previousModel.providerID}/${previousModel.modelID}` : undefined,
|
|
129811
|
+
failedError: errorInfo.message,
|
|
129812
|
+
nextModel: `${providerID}/${transformedModelId}`
|
|
129813
|
+
};
|
|
129814
|
+
onRetrying?.({
|
|
129815
|
+
task,
|
|
129816
|
+
source,
|
|
129817
|
+
previousSessionID,
|
|
129818
|
+
failedModel: task.retryNotification.failedModel,
|
|
129819
|
+
failedError: errorInfo.message,
|
|
129820
|
+
nextModel: `${providerID}/${transformedModelId}`
|
|
129821
|
+
});
|
|
129407
129822
|
const key = task.model ? `${task.model.providerID}/${task.model.modelID}` : task.agent;
|
|
129408
129823
|
const queue = queuesByKey.get(key) ?? [];
|
|
129409
129824
|
const retryInput = {
|
|
@@ -129415,7 +129830,7 @@ async function tryFallbackRetry(args) {
|
|
|
129415
129830
|
parentModel: task.parentModel,
|
|
129416
129831
|
parentAgent: task.parentAgent,
|
|
129417
129832
|
parentTools: task.parentTools,
|
|
129418
|
-
model:
|
|
129833
|
+
model: nextModel,
|
|
129419
129834
|
fallbackChain: task.fallbackChain,
|
|
129420
129835
|
category: task.category,
|
|
129421
129836
|
isUnstableAgent: task.isUnstableAgent
|
|
@@ -129423,7 +129838,7 @@ async function tryFallbackRetry(args) {
|
|
|
129423
129838
|
if (previousSessionID) {
|
|
129424
129839
|
await abortWithTimeout(client2, previousSessionID).catch(() => {});
|
|
129425
129840
|
}
|
|
129426
|
-
queue.push({ task, input: retryInput });
|
|
129841
|
+
queue.push({ task, input: retryInput, attemptID: nextAttempt.attemptID });
|
|
129427
129842
|
queuesByKey.set(key, queue);
|
|
129428
129843
|
processKey(key);
|
|
129429
129844
|
return true;
|
|
@@ -130041,10 +130456,37 @@ function resolveMessagePartInfo(properties) {
|
|
|
130041
130456
|
}
|
|
130042
130457
|
return properties;
|
|
130043
130458
|
}
|
|
130459
|
+
function formatAttemptModelSummary(attempt) {
|
|
130460
|
+
if (!attempt?.providerID || !attempt.modelID) {
|
|
130461
|
+
return;
|
|
130462
|
+
}
|
|
130463
|
+
return `${attempt.providerID}/${attempt.modelID}`;
|
|
130464
|
+
}
|
|
130465
|
+
function getPreviousAttempt(task, attemptID) {
|
|
130466
|
+
if (!attemptID || !task.attempts || task.attempts.length === 0) {
|
|
130467
|
+
return;
|
|
130468
|
+
}
|
|
130469
|
+
const attemptIndex = task.attempts.findIndex((attempt) => attempt.attemptID === attemptID);
|
|
130470
|
+
if (attemptIndex <= 0) {
|
|
130471
|
+
return;
|
|
130472
|
+
}
|
|
130473
|
+
return task.attempts[attemptIndex - 1];
|
|
130474
|
+
}
|
|
130475
|
+
function cloneAttempts(task) {
|
|
130476
|
+
if (!task.attempts) {
|
|
130477
|
+
return;
|
|
130478
|
+
}
|
|
130479
|
+
return task.attempts.map((attempt) => ({ ...attempt }));
|
|
130480
|
+
}
|
|
130481
|
+
function buildLocalSessionUrl(directory, sessionID) {
|
|
130482
|
+
const encodedDirectory = Buffer.from(directory).toString("base64url");
|
|
130483
|
+
return `http://127.0.0.1:4096/${encodedDirectory}/session/${sessionID}`;
|
|
130484
|
+
}
|
|
130044
130485
|
var MAX_TASK_REMOVAL_RESCHEDULES = 6;
|
|
130045
130486
|
|
|
130046
130487
|
class BackgroundManager {
|
|
130047
130488
|
tasks;
|
|
130489
|
+
tasksByParentSession;
|
|
130048
130490
|
notifications;
|
|
130049
130491
|
pendingNotifications;
|
|
130050
130492
|
pendingByParent;
|
|
@@ -130069,10 +130511,12 @@ class BackgroundManager {
|
|
|
130069
130511
|
rootDescendantCounts;
|
|
130070
130512
|
preStartDescendantReservations;
|
|
130071
130513
|
enableParentSessionNotifications;
|
|
130514
|
+
modelFallbackControllerAccessor;
|
|
130072
130515
|
taskHistory = new TaskHistory;
|
|
130073
130516
|
cachedCircuitBreakerSettings;
|
|
130074
130517
|
constructor(ctx, config4, options) {
|
|
130075
130518
|
this.tasks = new Map;
|
|
130519
|
+
this.tasksByParentSession = new Map;
|
|
130076
130520
|
this.notifications = new Map;
|
|
130077
130521
|
this.pendingNotifications = new Map;
|
|
130078
130522
|
this.pendingByParent = new Map;
|
|
@@ -130086,6 +130530,7 @@ class BackgroundManager {
|
|
|
130086
130530
|
this.rootDescendantCounts = new Map;
|
|
130087
130531
|
this.preStartDescendantReservations = new Set;
|
|
130088
130532
|
this.enableParentSessionNotifications = options?.enableParentSessionNotifications ?? true;
|
|
130533
|
+
this.modelFallbackControllerAccessor = options?.modelFallbackControllerAccessor;
|
|
130089
130534
|
this.registerProcessCleanup();
|
|
130090
130535
|
}
|
|
130091
130536
|
async abortSessionWithLogging(sessionID, reason) {
|
|
@@ -130158,6 +130603,42 @@ class BackgroundManager {
|
|
|
130158
130603
|
}
|
|
130159
130604
|
this.unregisterRootDescendant(task.rootSessionID);
|
|
130160
130605
|
}
|
|
130606
|
+
addTask(task) {
|
|
130607
|
+
this.tasks.set(task.id, task);
|
|
130608
|
+
if (!task.parentSessionID) {
|
|
130609
|
+
return;
|
|
130610
|
+
}
|
|
130611
|
+
const taskIDs = this.tasksByParentSession.get(task.parentSessionID) ?? new Set;
|
|
130612
|
+
taskIDs.add(task.id);
|
|
130613
|
+
this.tasksByParentSession.set(task.parentSessionID, taskIDs);
|
|
130614
|
+
}
|
|
130615
|
+
removeTask(task) {
|
|
130616
|
+
this.tasks.delete(task.id);
|
|
130617
|
+
this.removeTaskFromParentIndex(task.id, task.parentSessionID);
|
|
130618
|
+
}
|
|
130619
|
+
updateTaskParent(task, parentSessionID) {
|
|
130620
|
+
if (task.parentSessionID === parentSessionID) {
|
|
130621
|
+
return;
|
|
130622
|
+
}
|
|
130623
|
+
this.removeTaskFromParentIndex(task.id, task.parentSessionID);
|
|
130624
|
+
task.parentSessionID = parentSessionID;
|
|
130625
|
+
const taskIDs = this.tasksByParentSession.get(parentSessionID) ?? new Set;
|
|
130626
|
+
taskIDs.add(task.id);
|
|
130627
|
+
this.tasksByParentSession.set(parentSessionID, taskIDs);
|
|
130628
|
+
}
|
|
130629
|
+
removeTaskFromParentIndex(taskID, parentSessionID) {
|
|
130630
|
+
if (!parentSessionID) {
|
|
130631
|
+
return;
|
|
130632
|
+
}
|
|
130633
|
+
const taskIDs = this.tasksByParentSession.get(parentSessionID);
|
|
130634
|
+
if (!taskIDs) {
|
|
130635
|
+
return;
|
|
130636
|
+
}
|
|
130637
|
+
taskIDs.delete(taskID);
|
|
130638
|
+
if (taskIDs.size === 0) {
|
|
130639
|
+
this.tasksByParentSession.delete(parentSessionID);
|
|
130640
|
+
}
|
|
130641
|
+
}
|
|
130161
130642
|
async launch(input) {
|
|
130162
130643
|
log("[background-agent] launch() called with:", {
|
|
130163
130644
|
agent: input.agent,
|
|
@@ -130195,7 +130676,8 @@ class BackgroundManager {
|
|
|
130195
130676
|
attemptCount: 0,
|
|
130196
130677
|
category: input.category
|
|
130197
130678
|
};
|
|
130198
|
-
|
|
130679
|
+
const firstAttempt = startAttempt(task, input.model);
|
|
130680
|
+
this.addTask(task);
|
|
130199
130681
|
this.taskHistory.record(input.parentSessionID, { id: task.id, agent: input.agent, description: input.description, status: "pending", category: input.category });
|
|
130200
130682
|
if (input.parentSessionID) {
|
|
130201
130683
|
const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set;
|
|
@@ -130204,7 +130686,7 @@ class BackgroundManager {
|
|
|
130204
130686
|
}
|
|
130205
130687
|
const key = this.getConcurrencyKeyFromInput(input);
|
|
130206
130688
|
const queue = this.queuesByKey.get(key) ?? [];
|
|
130207
|
-
queue.push({ task, input });
|
|
130689
|
+
queue.push({ task, input, attemptID: firstAttempt.attemptID });
|
|
130208
130690
|
this.queuesByKey.set(key, queue);
|
|
130209
130691
|
log("[background-agent] Task queued:", { taskId: task.id, key, queueLength: queue.length });
|
|
130210
130692
|
const toastManager = getTaskToastManager();
|
|
@@ -130250,9 +130732,13 @@ class BackgroundManager {
|
|
|
130250
130732
|
} catch (error92) {
|
|
130251
130733
|
log("[background-agent] Error starting task:", error92);
|
|
130252
130734
|
this.rollbackPreStartDescendantReservation(item.task);
|
|
130253
|
-
item.task.
|
|
130254
|
-
|
|
130255
|
-
|
|
130735
|
+
if (item.task.currentAttemptID) {
|
|
130736
|
+
finalizeAttempt(item.task, item.task.currentAttemptID, "error", error92 instanceof Error ? error92.message : String(error92));
|
|
130737
|
+
} else {
|
|
130738
|
+
item.task.status = "error";
|
|
130739
|
+
item.task.error = error92 instanceof Error ? error92.message : String(error92);
|
|
130740
|
+
item.task.completedAt = new Date;
|
|
130741
|
+
}
|
|
130256
130742
|
if (item.task.concurrencyKey) {
|
|
130257
130743
|
this.concurrencyManager.release(item.task.concurrencyKey);
|
|
130258
130744
|
item.task.concurrencyKey = undefined;
|
|
@@ -130275,6 +130761,7 @@ class BackgroundManager {
|
|
|
130275
130761
|
}
|
|
130276
130762
|
async startTask(item) {
|
|
130277
130763
|
const { task, input } = item;
|
|
130764
|
+
const attemptID = item.attemptID ?? ensureCurrentAttempt(task, input.model).attemptID;
|
|
130278
130765
|
log("[background-agent] Starting task:", {
|
|
130279
130766
|
taskId: task.id,
|
|
130280
130767
|
agent: input.agent,
|
|
@@ -130344,15 +130831,49 @@ class BackgroundManager {
|
|
|
130344
130831
|
this.concurrencyManager.release(concurrencyKey);
|
|
130345
130832
|
return;
|
|
130346
130833
|
}
|
|
130347
|
-
|
|
130348
|
-
|
|
130349
|
-
|
|
130834
|
+
const boundAttempt = bindAttemptSession(task, attemptID, sessionID, input.model);
|
|
130835
|
+
if (!boundAttempt) {
|
|
130836
|
+
await this.abortSessionWithLogging(sessionID, "stale attempt binding cleanup");
|
|
130837
|
+
subagentSessions.delete(sessionID);
|
|
130838
|
+
if (task.rootSessionID) {
|
|
130839
|
+
this.unregisterRootDescendant(task.rootSessionID);
|
|
130840
|
+
}
|
|
130841
|
+
this.concurrencyManager.release(concurrencyKey);
|
|
130842
|
+
return;
|
|
130843
|
+
}
|
|
130350
130844
|
task.progress = {
|
|
130351
130845
|
toolCalls: 0,
|
|
130352
130846
|
lastUpdate: new Date
|
|
130353
130847
|
};
|
|
130354
130848
|
task.concurrencyKey = concurrencyKey;
|
|
130355
130849
|
task.concurrencyGroup = concurrencyKey;
|
|
130850
|
+
if (task.retryNotification) {
|
|
130851
|
+
const attemptNumber = boundAttempt.attemptNumber;
|
|
130852
|
+
const retrySessionUrl = buildLocalSessionUrl(parentDirectory, sessionID);
|
|
130853
|
+
const previousAttempt = getPreviousAttempt(task, boundAttempt.attemptID);
|
|
130854
|
+
const failedSessionID = previousAttempt?.sessionID ?? task.retryNotification.previousSessionID;
|
|
130855
|
+
const failedSessionLine = failedSessionID ? `
|
|
130856
|
+
- Failed session: \`${failedSessionID}\`` : "";
|
|
130857
|
+
const failedModel = formatAttemptModelSummary(previousAttempt) ?? task.retryNotification.failedModel;
|
|
130858
|
+
const failedModelLine = failedModel ? `
|
|
130859
|
+
- Failed model: \`${failedModel}\`` : "";
|
|
130860
|
+
const failedError = previousAttempt?.error ?? task.retryNotification.failedError;
|
|
130861
|
+
const failedErrorLine = failedError ? `
|
|
130862
|
+
- Error: ${failedError}` : "";
|
|
130863
|
+
const retryModel = formatAttemptModelSummary(boundAttempt) ?? task.retryNotification.nextModel;
|
|
130864
|
+
this.queuePendingNotification(task.parentSessionID, `<system-reminder>
|
|
130865
|
+
[BACKGROUND TASK RETRY SESSION READY]
|
|
130866
|
+
**ID:** \`${task.id}\`
|
|
130867
|
+
**Description:** ${task.description}
|
|
130868
|
+
**Retry attempt:** ${attemptNumber}
|
|
130869
|
+
**Retry session:** \`${sessionID}\`
|
|
130870
|
+
**Retry link:** ${retrySessionUrl}${failedSessionLine}${failedModelLine}${failedErrorLine}${retryModel ? `
|
|
130871
|
+
- Model: \`${retryModel}\`` : ""}
|
|
130872
|
+
|
|
130873
|
+
The fallback retry session is now created and can be inspected directly.
|
|
130874
|
+
</system-reminder>`);
|
|
130875
|
+
task.retryNotification = undefined;
|
|
130876
|
+
}
|
|
130356
130877
|
this.taskHistory.record(input.parentSessionID, { id: task.id, sessionID, agent: input.agent, description: input.description, status: "running", category: input.category, startedAt: task.startedAt });
|
|
130357
130878
|
this.startPolling();
|
|
130358
130879
|
log("[background-agent] Launching task:", { taskId: task.id, sessionID, agent: input.agent });
|
|
@@ -130416,16 +130937,33 @@ class BackgroundManager {
|
|
|
130416
130937
|
}
|
|
130417
130938
|
}
|
|
130418
130939
|
log("[background-agent] promptAsync error:", error92);
|
|
130419
|
-
const
|
|
130940
|
+
const resolvedTask = this.resolveTaskAttemptBySession(sessionID);
|
|
130941
|
+
const existingTask = resolvedTask?.task;
|
|
130942
|
+
if (resolvedTask && !resolvedTask.isCurrent) {
|
|
130943
|
+
log("[background-agent] Ignoring prompt error from stale attempt session", {
|
|
130944
|
+
sessionID,
|
|
130945
|
+
currentAttemptID: resolvedTask.task.currentAttemptID,
|
|
130946
|
+
attemptID: resolvedTask.attemptID
|
|
130947
|
+
});
|
|
130948
|
+
return;
|
|
130949
|
+
}
|
|
130420
130950
|
if (existingTask) {
|
|
130421
|
-
|
|
130422
|
-
|
|
130423
|
-
|
|
130424
|
-
|
|
130951
|
+
const errorInfo = {
|
|
130952
|
+
name: extractErrorName2(error92),
|
|
130953
|
+
message: extractErrorMessage(error92)
|
|
130954
|
+
};
|
|
130955
|
+
if (await this.tryFallbackRetry(existingTask, errorInfo, "promptAsync.launch")) {
|
|
130956
|
+
return;
|
|
130957
|
+
}
|
|
130958
|
+
const errorMessage = errorInfo.message ?? (error92 instanceof Error ? error92.message : String(error92));
|
|
130959
|
+
const terminalError = errorMessage.includes("agent.name") || errorMessage.includes("undefined") || isAgentNotFoundError(error92) ? `Agent "${input.agent}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.` : errorMessage;
|
|
130960
|
+
if (existingTask.currentAttemptID) {
|
|
130961
|
+
finalizeAttempt(existingTask, existingTask.currentAttemptID, "interrupt", terminalError);
|
|
130425
130962
|
} else {
|
|
130426
|
-
existingTask.
|
|
130963
|
+
existingTask.status = "interrupt";
|
|
130964
|
+
existingTask.error = terminalError;
|
|
130965
|
+
existingTask.completedAt = new Date;
|
|
130427
130966
|
}
|
|
130428
|
-
existingTask.completedAt = new Date;
|
|
130429
130967
|
if (existingTask.rootSessionID) {
|
|
130430
130968
|
this.unregisterRootDescendant(existingTask.rootSessionID);
|
|
130431
130969
|
}
|
|
@@ -130446,13 +130984,24 @@ class BackgroundManager {
|
|
|
130446
130984
|
return this.tasks.get(id);
|
|
130447
130985
|
}
|
|
130448
130986
|
getTasksByParentSession(sessionID) {
|
|
130449
|
-
const
|
|
130450
|
-
|
|
130451
|
-
|
|
130452
|
-
|
|
130987
|
+
const taskIDs = this.tasksByParentSession.get(sessionID);
|
|
130988
|
+
if (!taskIDs) {
|
|
130989
|
+
const result = [];
|
|
130990
|
+
for (const task of this.tasks.values()) {
|
|
130991
|
+
if (task.parentSessionID === sessionID) {
|
|
130992
|
+
result.push(task);
|
|
130993
|
+
}
|
|
130994
|
+
}
|
|
130995
|
+
return result;
|
|
130996
|
+
}
|
|
130997
|
+
const tasks = [];
|
|
130998
|
+
for (const taskID of taskIDs) {
|
|
130999
|
+
const task = this.tasks.get(taskID);
|
|
131000
|
+
if (task) {
|
|
131001
|
+
tasks.push(task);
|
|
130453
131002
|
}
|
|
130454
131003
|
}
|
|
130455
|
-
return
|
|
131004
|
+
return tasks;
|
|
130456
131005
|
}
|
|
130457
131006
|
getAllDescendantTasks(sessionID) {
|
|
130458
131007
|
const result = [];
|
|
@@ -130471,9 +131020,31 @@ class BackgroundManager {
|
|
|
130471
131020
|
if (task.sessionID === sessionID) {
|
|
130472
131021
|
return task;
|
|
130473
131022
|
}
|
|
131023
|
+
if (findAttemptBySession(task, sessionID)) {
|
|
131024
|
+
return task;
|
|
131025
|
+
}
|
|
130474
131026
|
}
|
|
130475
131027
|
return;
|
|
130476
131028
|
}
|
|
131029
|
+
resolveTaskAttemptBySession(sessionID) {
|
|
131030
|
+
const task = this.findBySession(sessionID);
|
|
131031
|
+
if (!task) {
|
|
131032
|
+
return;
|
|
131033
|
+
}
|
|
131034
|
+
const attempt = findAttemptBySession(task, sessionID);
|
|
131035
|
+
if (!attempt) {
|
|
131036
|
+
return {
|
|
131037
|
+
task,
|
|
131038
|
+
attemptID: undefined,
|
|
131039
|
+
isCurrent: task.sessionID === sessionID
|
|
131040
|
+
};
|
|
131041
|
+
}
|
|
131042
|
+
return {
|
|
131043
|
+
task,
|
|
131044
|
+
attemptID: attempt.attemptID,
|
|
131045
|
+
isCurrent: task.currentAttemptID === attempt.attemptID
|
|
131046
|
+
};
|
|
131047
|
+
}
|
|
130477
131048
|
getConcurrencyKeyFromInput(input) {
|
|
130478
131049
|
if (input.model) {
|
|
130479
131050
|
return `${input.model.providerID}/${input.model.modelID}`;
|
|
@@ -130486,7 +131057,7 @@ class BackgroundManager {
|
|
|
130486
131057
|
const parentChanged = input.parentSessionID !== existingTask.parentSessionID;
|
|
130487
131058
|
if (parentChanged) {
|
|
130488
131059
|
this.cleanupPendingByParent(existingTask);
|
|
130489
|
-
existingTask
|
|
131060
|
+
this.updateTaskParent(existingTask, input.parentSessionID);
|
|
130490
131061
|
}
|
|
130491
131062
|
if (input.parentAgent !== undefined) {
|
|
130492
131063
|
existingTask.parentAgent = input.parentAgent;
|
|
@@ -130530,7 +131101,7 @@ class BackgroundManager {
|
|
|
130530
131101
|
concurrencyKey: input.concurrencyKey,
|
|
130531
131102
|
concurrencyGroup
|
|
130532
131103
|
};
|
|
130533
|
-
this.
|
|
131104
|
+
this.addTask(task);
|
|
130534
131105
|
subagentSessions.add(input.sessionID);
|
|
130535
131106
|
this.startPolling();
|
|
130536
131107
|
this.taskHistory.record(input.parentSessionID, { id: task.id, sessionID: input.sessionID, agent: input.agent || "task", description: input.description, status: "running", startedAt: task.startedAt });
|
|
@@ -130569,7 +131140,7 @@ class BackgroundManager {
|
|
|
130569
131140
|
existingTask.status = "running";
|
|
130570
131141
|
existingTask.completedAt = undefined;
|
|
130571
131142
|
existingTask.error = undefined;
|
|
130572
|
-
existingTask
|
|
131143
|
+
this.updateTaskParent(existingTask, input.parentSessionID);
|
|
130573
131144
|
existingTask.parentMessageID = input.parentMessageID;
|
|
130574
131145
|
existingTask.parentModel = input.parentModel;
|
|
130575
131146
|
existingTask.parentAgent = input.parentAgent;
|
|
@@ -130636,8 +131207,15 @@ class BackgroundManager {
|
|
|
130636
131207
|
}
|
|
130637
131208
|
}).catch(async (error92) => {
|
|
130638
131209
|
log("[background-agent] resume prompt error:", error92);
|
|
131210
|
+
const errorInfo = {
|
|
131211
|
+
name: extractErrorName2(error92),
|
|
131212
|
+
message: extractErrorMessage(error92)
|
|
131213
|
+
};
|
|
131214
|
+
if (await this.tryFallbackRetry(existingTask, errorInfo, "promptAsync.resume")) {
|
|
131215
|
+
return;
|
|
131216
|
+
}
|
|
130639
131217
|
existingTask.status = "interrupt";
|
|
130640
|
-
const errorMessage = error92 instanceof Error ? error92.message : String(error92);
|
|
131218
|
+
const errorMessage = errorInfo.message ?? (error92 instanceof Error ? error92.message : String(error92));
|
|
130641
131219
|
existingTask.error = errorMessage;
|
|
130642
131220
|
existingTask.completedAt = new Date;
|
|
130643
131221
|
if (existingTask.rootSessionID) {
|
|
@@ -130720,8 +131298,11 @@ class BackgroundManager {
|
|
|
130720
131298
|
}
|
|
130721
131299
|
if (role !== "assistant")
|
|
130722
131300
|
return;
|
|
130723
|
-
const
|
|
130724
|
-
if (!
|
|
131301
|
+
const resolved = this.resolveTaskAttemptBySession(sessionID);
|
|
131302
|
+
if (!resolved?.isCurrent)
|
|
131303
|
+
return;
|
|
131304
|
+
const { task } = resolved;
|
|
131305
|
+
if (task.status !== "running")
|
|
130725
131306
|
return;
|
|
130726
131307
|
const assistantError = info["error"];
|
|
130727
131308
|
if (!assistantError)
|
|
@@ -130742,9 +131323,10 @@ class BackgroundManager {
|
|
|
130742
131323
|
const sessionID = partInfo?.sessionID;
|
|
130743
131324
|
if (!sessionID)
|
|
130744
131325
|
return;
|
|
130745
|
-
const
|
|
130746
|
-
if (!
|
|
131326
|
+
const resolved = this.resolveTaskAttemptBySession(sessionID);
|
|
131327
|
+
if (!resolved?.isCurrent)
|
|
130747
131328
|
return;
|
|
131329
|
+
const { task } = resolved;
|
|
130748
131330
|
if (this.hasOutputSignalFromPart(partInfo)) {
|
|
130749
131331
|
this.markSessionOutputObserved(sessionID);
|
|
130750
131332
|
}
|
|
@@ -130829,7 +131411,10 @@ class BackgroundManager {
|
|
|
130829
131411
|
return;
|
|
130830
131412
|
handleSessionIdleBackgroundEvent({
|
|
130831
131413
|
properties: props,
|
|
130832
|
-
findBySession: (id) =>
|
|
131414
|
+
findBySession: (id) => {
|
|
131415
|
+
const resolved = this.resolveTaskAttemptBySession(id);
|
|
131416
|
+
return resolved?.isCurrent ? resolved.task : undefined;
|
|
131417
|
+
},
|
|
130833
131418
|
idleDeferralTimers: this.idleDeferralTimers,
|
|
130834
131419
|
validateSessionHasOutput: (id) => this.validateSessionHasOutput(id),
|
|
130835
131420
|
checkSessionTodos: (id) => this.checkSessionTodos(id),
|
|
@@ -130841,8 +131426,11 @@ class BackgroundManager {
|
|
|
130841
131426
|
const sessionID = typeof props?.sessionID === "string" ? props.sessionID : undefined;
|
|
130842
131427
|
if (!sessionID)
|
|
130843
131428
|
return;
|
|
130844
|
-
const
|
|
130845
|
-
if (!
|
|
131429
|
+
const resolved = this.resolveTaskAttemptBySession(sessionID);
|
|
131430
|
+
if (!resolved?.isCurrent)
|
|
131431
|
+
return;
|
|
131432
|
+
const { task } = resolved;
|
|
131433
|
+
if (task.status !== "running")
|
|
130846
131434
|
return;
|
|
130847
131435
|
const errorObj = props?.error;
|
|
130848
131436
|
const errorName = errorObj?.name;
|
|
@@ -130869,9 +131457,9 @@ class BackgroundManager {
|
|
|
130869
131457
|
this.clearSessionOutputObserved(sessionID);
|
|
130870
131458
|
this.clearSessionTodoObservation(sessionID);
|
|
130871
131459
|
const tasksToCancel = new Map;
|
|
130872
|
-
const directTask = this.
|
|
130873
|
-
if (directTask) {
|
|
130874
|
-
tasksToCancel.set(directTask.id, directTask);
|
|
131460
|
+
const directTask = this.resolveTaskAttemptBySession(sessionID);
|
|
131461
|
+
if (directTask?.isCurrent) {
|
|
131462
|
+
tasksToCancel.set(directTask.task.id, directTask.task);
|
|
130875
131463
|
}
|
|
130876
131464
|
for (const descendant of this.getAllDescendantTasks(sessionID)) {
|
|
130877
131465
|
tasksToCancel.set(descendant.id, descendant);
|
|
@@ -130917,8 +131505,11 @@ class BackgroundManager {
|
|
|
130917
131505
|
const status = props?.status;
|
|
130918
131506
|
if (!sessionID || status?.type !== "retry")
|
|
130919
131507
|
return;
|
|
130920
|
-
const
|
|
130921
|
-
if (!
|
|
131508
|
+
const resolved = this.resolveTaskAttemptBySession(sessionID);
|
|
131509
|
+
if (!resolved?.isCurrent)
|
|
131510
|
+
return;
|
|
131511
|
+
const { task } = resolved;
|
|
131512
|
+
if (task.status !== "running")
|
|
130922
131513
|
return;
|
|
130923
131514
|
const errorMessage = typeof status.message === "string" ? status.message : undefined;
|
|
130924
131515
|
const errorInfo = { name: "SessionRetry", message: errorMessage };
|
|
@@ -130932,6 +131523,12 @@ class BackgroundManager {
|
|
|
130932
131523
|
}
|
|
130933
131524
|
async handleSessionErrorEvent(args) {
|
|
130934
131525
|
const { task, errorInfo, errorMessage, errorName } = args;
|
|
131526
|
+
if (!task.fallbackChain && task.sessionID) {
|
|
131527
|
+
const sessionFallbackChain = this.modelFallbackControllerAccessor?.getSessionFallbackChain(task.sessionID);
|
|
131528
|
+
if (sessionFallbackChain?.length) {
|
|
131529
|
+
task.fallbackChain = sessionFallbackChain;
|
|
131530
|
+
}
|
|
131531
|
+
}
|
|
130935
131532
|
if (isAgentNotFoundError({ message: errorInfo.message })) {
|
|
130936
131533
|
log("[background-agent] Skipping session.error fallback for agent-not-found (handled by prompt catch)", {
|
|
130937
131534
|
taskId: task.id,
|
|
@@ -130951,9 +131548,13 @@ class BackgroundManager {
|
|
|
130951
131548
|
hasFallbackChain: !!task.fallbackChain,
|
|
130952
131549
|
canRetry
|
|
130953
131550
|
});
|
|
130954
|
-
task.
|
|
130955
|
-
|
|
130956
|
-
|
|
131551
|
+
if (task.currentAttemptID) {
|
|
131552
|
+
finalizeAttempt(task, task.currentAttemptID, "error", errorMsg);
|
|
131553
|
+
} else {
|
|
131554
|
+
task.status = "error";
|
|
131555
|
+
task.error = errorMsg;
|
|
131556
|
+
task.completedAt = new Date;
|
|
131557
|
+
}
|
|
130957
131558
|
if (task.rootSessionID) {
|
|
130958
131559
|
this.unregisterRootDescendant(task.rootSessionID);
|
|
130959
131560
|
}
|
|
@@ -130997,7 +131598,28 @@ class BackgroundManager {
|
|
|
130997
131598
|
client: this.client,
|
|
130998
131599
|
idleDeferralTimers: this.idleDeferralTimers,
|
|
130999
131600
|
queuesByKey: this.queuesByKey,
|
|
131000
|
-
processKey: (key) => this.processKey(key)
|
|
131601
|
+
processKey: (key) => this.processKey(key),
|
|
131602
|
+
onRetrying: ({ task: task2, source: source2 }) => {
|
|
131603
|
+
const currentAttempt = getCurrentAttempt(task2);
|
|
131604
|
+
const previousAttempt = getPreviousAttempt(task2, currentAttempt?.attemptID);
|
|
131605
|
+
const sourceText = source2 ? ` via ${source2}` : "";
|
|
131606
|
+
const failedSessionLine = previousAttempt?.sessionID ? `
|
|
131607
|
+
- Failed session: \`${previousAttempt.sessionID}\`` : "";
|
|
131608
|
+
const failedModel = formatAttemptModelSummary(previousAttempt);
|
|
131609
|
+
const failedModelLine = failedModel ? `
|
|
131610
|
+
- Failed model: \`${failedModel}\`` : "";
|
|
131611
|
+
const failedErrorLine = previousAttempt?.error ? `
|
|
131612
|
+
- Error: ${previousAttempt.error}` : "";
|
|
131613
|
+
const nextModel = formatAttemptModelSummary(currentAttempt);
|
|
131614
|
+
this.queuePendingNotification(task2.parentSessionID, `<system-reminder>
|
|
131615
|
+
[BACKGROUND TASK RETRYING]
|
|
131616
|
+
**ID:** \`${task2.id}\`
|
|
131617
|
+
**Description:** ${task2.description}${sourceText}${failedSessionLine}${failedModelLine}${failedErrorLine}${nextModel ? `
|
|
131618
|
+
- Next model: \`${nextModel}\`` : ""}
|
|
131619
|
+
|
|
131620
|
+
The task was re-queued on a fallback model after a retryable failure.
|
|
131621
|
+
</system-reminder>`);
|
|
131622
|
+
}
|
|
131001
131623
|
});
|
|
131002
131624
|
return result.then((retried) => {
|
|
131003
131625
|
if (retried && previousSessionID) {
|
|
@@ -131129,7 +131751,7 @@ ${originalText}`;
|
|
|
131129
131751
|
}
|
|
131130
131752
|
}
|
|
131131
131753
|
this.clearNotificationsForTask(taskId);
|
|
131132
|
-
this.
|
|
131754
|
+
this.removeTask(task);
|
|
131133
131755
|
this.clearTaskHistoryWhenParentTasksGone(task.parentSessionID);
|
|
131134
131756
|
if (task.sessionID) {
|
|
131135
131757
|
subagentSessions.delete(task.sessionID);
|
|
@@ -131163,14 +131785,18 @@ ${originalText}`;
|
|
|
131163
131785
|
log("[background-agent] Cancelled pending task:", { taskId, key });
|
|
131164
131786
|
}
|
|
131165
131787
|
const wasRunning = task.status === "running";
|
|
131166
|
-
task.
|
|
131167
|
-
|
|
131788
|
+
if (task.currentAttemptID) {
|
|
131789
|
+
finalizeAttempt(task, task.currentAttemptID, "cancelled", reason);
|
|
131790
|
+
} else {
|
|
131791
|
+
task.status = "cancelled";
|
|
131792
|
+
task.completedAt = new Date;
|
|
131793
|
+
if (reason) {
|
|
131794
|
+
task.error = reason;
|
|
131795
|
+
}
|
|
131796
|
+
}
|
|
131168
131797
|
if (wasRunning && task.rootSessionID) {
|
|
131169
131798
|
this.unregisterRootDescendant(task.rootSessionID);
|
|
131170
131799
|
}
|
|
131171
|
-
if (reason) {
|
|
131172
|
-
task.error = reason;
|
|
131173
|
-
}
|
|
131174
131800
|
this.taskHistory.record(task.parentSessionID, { id: task.id, sessionID: task.sessionID, agent: task.agent, description: task.description, status: "cancelled", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt });
|
|
131175
131801
|
if (task.concurrencyKey) {
|
|
131176
131802
|
this.concurrencyManager.release(task.concurrencyKey);
|
|
@@ -131245,8 +131871,12 @@ ${originalText}`;
|
|
|
131245
131871
|
log("[background-agent] Task already completed, skipping:", { taskId: task.id, status: task.status, source });
|
|
131246
131872
|
return false;
|
|
131247
131873
|
}
|
|
131248
|
-
task.
|
|
131249
|
-
|
|
131874
|
+
if (task.currentAttemptID) {
|
|
131875
|
+
finalizeAttempt(task, task.currentAttemptID, "completed");
|
|
131876
|
+
} else {
|
|
131877
|
+
task.status = "completed";
|
|
131878
|
+
task.completedAt = new Date;
|
|
131879
|
+
}
|
|
131250
131880
|
this.taskHistory.record(task.parentSessionID, { id: task.id, sessionID: task.sessionID, agent: task.agent, description: task.description, status: "completed", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt });
|
|
131251
131881
|
if (task.rootSessionID) {
|
|
131252
131882
|
this.unregisterRootDescendant(task.rootSessionID);
|
|
@@ -131292,7 +131922,8 @@ ${originalText}`;
|
|
|
131292
131922
|
id: task.id,
|
|
131293
131923
|
description: task.description,
|
|
131294
131924
|
status: task.status,
|
|
131295
|
-
error: task.error
|
|
131925
|
+
error: task.error,
|
|
131926
|
+
attempts: cloneAttempts(task)
|
|
131296
131927
|
});
|
|
131297
131928
|
const pendingSet = this.pendingByParent.get(task.parentSessionID);
|
|
131298
131929
|
let allComplete = false;
|
|
@@ -131308,7 +131939,7 @@ ${originalText}`;
|
|
|
131308
131939
|
remainingCount = Array.from(this.tasks.values()).filter((t) => t.parentSessionID === task.parentSessionID && t.id !== task.id && (t.status === "running" || t.status === "pending")).length;
|
|
131309
131940
|
allComplete = remainingCount === 0;
|
|
131310
131941
|
}
|
|
131311
|
-
const completedTasks = allComplete ? this.completedTaskSummaries.get(task.parentSessionID) ?? [{ id: task.id, description: task.description, status: task.status, error: task.error }] : [];
|
|
131942
|
+
const completedTasks = allComplete ? this.completedTaskSummaries.get(task.parentSessionID) ?? [{ id: task.id, description: task.description, status: task.status, error: task.error, attempts: cloneAttempts(task) }] : [];
|
|
131312
131943
|
if (allComplete) {
|
|
131313
131944
|
this.completedTaskSummaries.delete(task.parentSessionID);
|
|
131314
131945
|
}
|
|
@@ -131470,9 +132101,13 @@ ${originalText}`;
|
|
|
131470
132101
|
return verifySessionExists(this.client, sessionID, this.directory);
|
|
131471
132102
|
}
|
|
131472
132103
|
async failCrashedTask(task, errorMessage) {
|
|
131473
|
-
task.
|
|
131474
|
-
|
|
131475
|
-
|
|
132104
|
+
if (task.currentAttemptID) {
|
|
132105
|
+
finalizeAttempt(task, task.currentAttemptID, "error", errorMessage);
|
|
132106
|
+
} else {
|
|
132107
|
+
task.status = "error";
|
|
132108
|
+
task.error = errorMessage;
|
|
132109
|
+
task.completedAt = new Date;
|
|
132110
|
+
}
|
|
131476
132111
|
if (task.rootSessionID) {
|
|
131477
132112
|
this.unregisterRootDescendant(task.rootSessionID);
|
|
131478
132113
|
}
|
|
@@ -131640,6 +132275,7 @@ ${originalText}`;
|
|
|
131640
132275
|
}
|
|
131641
132276
|
this.concurrencyManager.clear();
|
|
131642
132277
|
this.tasks.clear();
|
|
132278
|
+
this.tasksByParentSession.clear();
|
|
131643
132279
|
this.notifications.clear();
|
|
131644
132280
|
this.pendingNotifications.clear();
|
|
131645
132281
|
this.pendingByParent.clear();
|
|
@@ -136876,12 +137512,16 @@ function createModelFallbackControllerAccessor() {
|
|
|
136876
137512
|
function setSessionFallbackChain2(sessionID, fallbackChain) {
|
|
136877
137513
|
controller?.setSessionFallbackChain(sessionID, fallbackChain);
|
|
136878
137514
|
}
|
|
137515
|
+
function getSessionFallbackChain(sessionID) {
|
|
137516
|
+
return controller?.getSessionFallbackChain(sessionID);
|
|
137517
|
+
}
|
|
136879
137518
|
function clearSessionFallbackChain2(sessionID) {
|
|
136880
137519
|
controller?.clearSessionFallbackChain(sessionID);
|
|
136881
137520
|
}
|
|
136882
137521
|
return {
|
|
136883
137522
|
register,
|
|
136884
137523
|
setSessionFallbackChain: setSessionFallbackChain2,
|
|
137524
|
+
getSessionFallbackChain,
|
|
136885
137525
|
clearSessionFallbackChain: clearSessionFallbackChain2
|
|
136886
137526
|
};
|
|
136887
137527
|
}
|
|
@@ -139777,6 +140417,12 @@ async function loadMcpConfigs(disabledMcps = []) {
|
|
|
139777
140417
|
}
|
|
139778
140418
|
return { servers, loadedServers };
|
|
139779
140419
|
}
|
|
140420
|
+
// src/agents/index.ts
|
|
140421
|
+
init_types();
|
|
140422
|
+
|
|
140423
|
+
// src/agents/sisyphus.ts
|
|
140424
|
+
init_types();
|
|
140425
|
+
|
|
139780
140426
|
// src/agents/sisyphus/gemini.ts
|
|
139781
140427
|
function buildGeminiToolMandate() {
|
|
139782
140428
|
return `<TOOL_CALL_MANDATE>
|
|
@@ -140920,6 +141566,7 @@ ${antiPatterns}
|
|
|
140920
141566
|
}
|
|
140921
141567
|
|
|
140922
141568
|
// src/agents/gpt-apply-patch-guard.ts
|
|
141569
|
+
init_types();
|
|
140923
141570
|
var GPT_APPLY_PATCH_GUIDANCE = "Use the `edit` and `write` tools for file changes. Do not use `apply_patch` on GPT models - it is unreliable here and can hang during verification.";
|
|
140924
141571
|
function getGptApplyPatchPermission(model) {
|
|
140925
141572
|
return isGptModel(model) ? { apply_patch: "deny" } : {};
|
|
@@ -142025,6 +142672,7 @@ ${styleBlock}`;
|
|
|
142025
142672
|
}
|
|
142026
142673
|
|
|
142027
142674
|
// src/agents/frontier-tool-schema-guard.ts
|
|
142675
|
+
init_types();
|
|
142028
142676
|
var FRONTIER_TOOL_SCHEMA_NAMES = ["grep", "glob"];
|
|
142029
142677
|
function isOpus47Model(model) {
|
|
142030
142678
|
const modelName = model.includes("/") ? model.split("/").pop() ?? model : model;
|
|
@@ -142576,6 +143224,7 @@ ${buildGeminiVerificationOverride()}
|
|
|
142576
143224
|
createSisyphusAgent.mode = MODE;
|
|
142577
143225
|
|
|
142578
143226
|
// src/agents/oracle.ts
|
|
143227
|
+
init_types();
|
|
142579
143228
|
var MODE2 = "subagent";
|
|
142580
143229
|
var ORACLE_PROMPT_METADATA = {
|
|
142581
143230
|
category: "advisor",
|
|
@@ -143789,6 +144438,9 @@ var metisPromptMetadata = {
|
|
|
143789
144438
|
keyTrigger: "Ambiguous or complex request \u2192 consult Metis before Prometheus"
|
|
143790
144439
|
};
|
|
143791
144440
|
|
|
144441
|
+
// src/agents/atlas/agent.ts
|
|
144442
|
+
init_types();
|
|
144443
|
+
|
|
143792
144444
|
// src/agents/atlas/shared-prompt.ts
|
|
143793
144445
|
var ATLAS_DELEGATION_SYSTEM = `<delegation_system>
|
|
143794
144446
|
## How to Delegate
|
|
@@ -145015,6 +145667,7 @@ var atlasPromptMetadata = {
|
|
|
145015
145667
|
keyTrigger: "Todo list path provided OR multiple tasks requiring multi-agent orchestration"
|
|
145016
145668
|
};
|
|
145017
145669
|
// src/agents/momus.ts
|
|
145670
|
+
init_types();
|
|
145018
145671
|
var MODE8 = "subagent";
|
|
145019
145672
|
var MOMUS_DEFAULT_PROMPT = `You are a **practical** work plan reviewer. Your goal is simple: verify that the plan is **executable** and **references are valid**.
|
|
145020
145673
|
|
|
@@ -145319,6 +145972,9 @@ var momusPromptMetadata = {
|
|
|
145319
145972
|
keyTrigger: 'Work plan saved to `.sisyphus/plans/*.md` \u2192 invoke Momus with the file path as the sole prompt (e.g. `prompt=".sisyphus/plans/my-plan.md"`). Do NOT invoke Momus for inline plans or todo lists.'
|
|
145320
145973
|
};
|
|
145321
145974
|
|
|
145975
|
+
// src/agents/hephaestus/agent.ts
|
|
145976
|
+
init_types();
|
|
145977
|
+
|
|
145322
145978
|
// src/agents/hephaestus/gpt.ts
|
|
145323
145979
|
function buildTodoDisciplineSection(useTaskSystem) {
|
|
145324
145980
|
if (useTaskSystem) {
|
|
@@ -147816,6 +148472,7 @@ No tasks on multi-step work = INCOMPLETE WORK. The user tracks your progress thr
|
|
|
147816
148472
|
No todos on multi-step work = INCOMPLETE WORK. The user tracks your progress through todos.`;
|
|
147817
148473
|
}
|
|
147818
148474
|
// src/agents/sisyphus-junior/agent.ts
|
|
148475
|
+
init_types();
|
|
147819
148476
|
var MODE11 = "subagent";
|
|
147820
148477
|
var BLOCKED_TOOLS3 = ["task"];
|
|
147821
148478
|
var GPT_BLOCKED_TOOLS = ["task", "apply_patch"];
|
|
@@ -150618,6 +151275,7 @@ function getGeminiPrometheusPrompt() {
|
|
|
150618
151275
|
}
|
|
150619
151276
|
|
|
150620
151277
|
// src/agents/prometheus/system-prompt.ts
|
|
151278
|
+
init_types();
|
|
150621
151279
|
var PROMETHEUS_SYSTEM_PROMPT = `${PROMETHEUS_IDENTITY_CONSTRAINTS}
|
|
150622
151280
|
${PROMETHEUS_INTERVIEW_MODE}
|
|
150623
151281
|
${PROMETHEUS_PLAN_GENERATION}
|
|
@@ -151513,6 +152171,7 @@ function createManagers(args) {
|
|
|
151513
152171
|
deps.markServerRunningInProcessFn();
|
|
151514
152172
|
}
|
|
151515
152173
|
const tmuxSessionManager = new deps.TmuxSessionManagerClass(ctx, tmuxConfig);
|
|
152174
|
+
const modelFallbackControllerAccessor = createModelFallbackControllerAccessor();
|
|
151516
152175
|
deps.registerManagerForCleanupFn({
|
|
151517
152176
|
shutdown: async () => {
|
|
151518
152177
|
await tmuxSessionManager.cleanup().catch((error92) => {
|
|
@@ -151556,7 +152215,8 @@ function createManagers(args) {
|
|
|
151556
152215
|
log("[create-managers] tmux cleanup error during shutdown:", error92);
|
|
151557
152216
|
});
|
|
151558
152217
|
},
|
|
151559
|
-
enableParentSessionNotifications: backgroundNotificationHookEnabled
|
|
152218
|
+
enableParentSessionNotifications: backgroundNotificationHookEnabled,
|
|
152219
|
+
modelFallbackControllerAccessor
|
|
151560
152220
|
});
|
|
151561
152221
|
deps.initTaskToastManagerFn(ctx.client);
|
|
151562
152222
|
const skillMcpManager = new deps.SkillMcpManagerClass;
|
|
@@ -151565,7 +152225,6 @@ function createManagers(args) {
|
|
|
151565
152225
|
pluginConfig,
|
|
151566
152226
|
modelCacheState
|
|
151567
152227
|
});
|
|
151568
|
-
const modelFallbackControllerAccessor = createModelFallbackControllerAccessor();
|
|
151569
152228
|
return {
|
|
151570
152229
|
tmuxSessionManager,
|
|
151571
152230
|
backgroundManager,
|
|
@@ -152706,15 +153365,13 @@ function extractErrorMessage3(error92) {
|
|
|
152706
153365
|
return "";
|
|
152707
153366
|
if (typeof error92 === "string")
|
|
152708
153367
|
return error92;
|
|
152709
|
-
if (error92 instanceof Error)
|
|
152710
|
-
return error92.message;
|
|
152711
153368
|
if (isRecord19(error92)) {
|
|
152712
153369
|
const candidates = [
|
|
152713
|
-
error92,
|
|
152714
153370
|
error92.data,
|
|
152715
|
-
error92.error,
|
|
152716
153371
|
isRecord19(error92.data) ? error92.data.error : undefined,
|
|
152717
|
-
error92.
|
|
153372
|
+
error92.error,
|
|
153373
|
+
error92.cause,
|
|
153374
|
+
error92
|
|
152718
153375
|
];
|
|
152719
153376
|
for (const candidate of candidates) {
|
|
152720
153377
|
if (isRecord19(candidate) && typeof candidate.message === "string" && candidate.message.length > 0) {
|
|
@@ -152722,6 +153379,8 @@ function extractErrorMessage3(error92) {
|
|
|
152722
153379
|
}
|
|
152723
153380
|
}
|
|
152724
153381
|
}
|
|
153382
|
+
if (error92 instanceof Error)
|
|
153383
|
+
return error92.message;
|
|
152725
153384
|
try {
|
|
152726
153385
|
return JSON.stringify(error92);
|
|
152727
153386
|
} catch {
|
|
@@ -153011,6 +153670,9 @@ function createEventHandler2(args) {
|
|
|
153011
153670
|
const sessionID = info?.sessionID;
|
|
153012
153671
|
const agent = info?.agent;
|
|
153013
153672
|
const role = info?.role;
|
|
153673
|
+
if (sessionID && info?.finish === true) {
|
|
153674
|
+
invalidateContextWindowUsageCache(pluginContext, sessionID);
|
|
153675
|
+
}
|
|
153014
153676
|
if (sessionID && role === "user") {
|
|
153015
153677
|
const isCompactionMessage2 = agent ? isCompactionAgent5(agent) : false;
|
|
153016
153678
|
if (agent && !isCompactionMessage2) {
|