oh-my-opencode 3.0.0-beta.1 → 3.0.0-beta.3
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/README.ja.md +13 -10
- package/README.md +15 -12
- package/README.zh-cn.md +13 -10
- package/dist/agents/metis.d.ts +1 -0
- package/dist/agents/orchestrator-sisyphus.d.ts +2 -1
- package/dist/cli/index.js +10 -4
- package/dist/config/schema.d.ts +204 -0
- package/dist/features/background-agent/manager.d.ts +15 -0
- package/dist/features/background-agent/types.d.ts +4 -0
- package/dist/hooks/auto-update-checker/index.d.ts +3 -0
- package/dist/hooks/auto-update-checker/index.test.d.ts +1 -0
- package/dist/hooks/background-compaction/index.d.ts +19 -0
- package/dist/hooks/background-notification/index.d.ts +6 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.js +457 -126
- package/dist/tools/skill/tools.d.ts +1 -7
- package/dist/tools/slashcommand/tools.d.ts +1 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19567,6 +19567,18 @@ async function runBunInstallWithDetails() {
|
|
|
19567
19567
|
|
|
19568
19568
|
// src/hooks/auto-update-checker/index.ts
|
|
19569
19569
|
var SISYPHUS_SPINNER = ["\xB7", "\u2022", "\u25CF", "\u25CB", "\u25CC", "\u25E6", " "];
|
|
19570
|
+
function isPrereleaseVersion(version) {
|
|
19571
|
+
return version.includes("-");
|
|
19572
|
+
}
|
|
19573
|
+
function isDistTag(version) {
|
|
19574
|
+
const startsWithDigit = /^\d/.test(version);
|
|
19575
|
+
return !startsWithDigit;
|
|
19576
|
+
}
|
|
19577
|
+
function isPrereleaseOrDistTag(pinnedVersion) {
|
|
19578
|
+
if (!pinnedVersion)
|
|
19579
|
+
return false;
|
|
19580
|
+
return isPrereleaseVersion(pinnedVersion) || isDistTag(pinnedVersion);
|
|
19581
|
+
}
|
|
19570
19582
|
function createAutoUpdateCheckerHook(ctx, options = {}) {
|
|
19571
19583
|
const { showStartupToast = true, isSisyphusEnabled = false, autoUpdate = true } = options;
|
|
19572
19584
|
const getToastMessage = (isUpdate, latestVersion) => {
|
|
@@ -19637,7 +19649,15 @@ async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
|
|
|
19637
19649
|
log("[auto-update-checker] Auto-update disabled, notification only");
|
|
19638
19650
|
return;
|
|
19639
19651
|
}
|
|
19652
|
+
if (isPrereleaseVersion(currentVersion)) {
|
|
19653
|
+
log(`[auto-update-checker] Skipping auto-update for prerelease version: ${currentVersion}`);
|
|
19654
|
+
return;
|
|
19655
|
+
}
|
|
19640
19656
|
if (pluginInfo.isPinned) {
|
|
19657
|
+
if (isPrereleaseOrDistTag(pluginInfo.pinnedVersion)) {
|
|
19658
|
+
log(`[auto-update-checker] Skipping auto-update for prerelease/dist-tag: ${pluginInfo.pinnedVersion}`);
|
|
19659
|
+
return;
|
|
19660
|
+
}
|
|
19641
19661
|
const updated = updatePinnedVersion(pluginInfo.configPath, pluginInfo.entry, latestVersion);
|
|
19642
19662
|
if (!updated) {
|
|
19643
19663
|
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
|
|
@@ -19755,6 +19775,8 @@ var TARGET_TOOLS = new Set([
|
|
|
19755
19775
|
"safe_glob",
|
|
19756
19776
|
"webfetch",
|
|
19757
19777
|
"context7_resolve-library-id",
|
|
19778
|
+
"context7_query-docs",
|
|
19779
|
+
"websearch_web_search_exa",
|
|
19758
19780
|
"context7_get-library-docs",
|
|
19759
19781
|
"grep_app_searchgithub"
|
|
19760
19782
|
]);
|
|
@@ -44131,8 +44153,8 @@ Session ID: ${task.sessionID}
|
|
|
44131
44153
|
|
|
44132
44154
|
(No messages found)`;
|
|
44133
44155
|
}
|
|
44134
|
-
const
|
|
44135
|
-
if (
|
|
44156
|
+
const relevantMessages = messages.filter((m2) => m2.info?.role === "assistant" || m2.info?.role === "tool");
|
|
44157
|
+
if (relevantMessages.length === 0) {
|
|
44136
44158
|
return `Task Result
|
|
44137
44159
|
|
|
44138
44160
|
Task ID: ${task.id}
|
|
@@ -44142,11 +44164,34 @@ Session ID: ${task.sessionID}
|
|
|
44142
44164
|
|
|
44143
44165
|
---
|
|
44144
44166
|
|
|
44145
|
-
(No assistant response found)`;
|
|
44167
|
+
(No assistant or tool response found)`;
|
|
44146
44168
|
}
|
|
44147
|
-
const
|
|
44148
|
-
|
|
44149
|
-
|
|
44169
|
+
const sortedMessages = [...relevantMessages].sort((a, b3) => {
|
|
44170
|
+
const timeA = String(a.info?.time ?? "");
|
|
44171
|
+
const timeB = String(b3.info?.time ?? "");
|
|
44172
|
+
return timeA.localeCompare(timeB);
|
|
44173
|
+
});
|
|
44174
|
+
const extractedContent = [];
|
|
44175
|
+
for (const message of sortedMessages) {
|
|
44176
|
+
for (const part of message.parts ?? []) {
|
|
44177
|
+
if ((part.type === "text" || part.type === "reasoning") && part.text) {
|
|
44178
|
+
extractedContent.push(part.text);
|
|
44179
|
+
} else if (part.type === "tool_result") {
|
|
44180
|
+
const toolResult = part;
|
|
44181
|
+
if (typeof toolResult.content === "string" && toolResult.content) {
|
|
44182
|
+
extractedContent.push(toolResult.content);
|
|
44183
|
+
} else if (Array.isArray(toolResult.content)) {
|
|
44184
|
+
for (const block of toolResult.content) {
|
|
44185
|
+
if ((block.type === "text" || block.type === "reasoning") && block.text) {
|
|
44186
|
+
extractedContent.push(block.text);
|
|
44187
|
+
}
|
|
44188
|
+
}
|
|
44189
|
+
}
|
|
44190
|
+
}
|
|
44191
|
+
}
|
|
44192
|
+
}
|
|
44193
|
+
const textContent = extractedContent.filter((text) => text.length > 0).join(`
|
|
44194
|
+
|
|
44150
44195
|
`);
|
|
44151
44196
|
const duration3 = formatDuration(task.startedAt, task.completedAt);
|
|
44152
44197
|
return `Task Result
|
|
@@ -44409,19 +44454,43 @@ session_id: ${sessionID}
|
|
|
44409
44454
|
}
|
|
44410
44455
|
const messages = messagesResult.data;
|
|
44411
44456
|
log(`[call_omo_agent] Got ${messages.length} messages`);
|
|
44412
|
-
const
|
|
44413
|
-
if (
|
|
44414
|
-
log(`[call_omo_agent] No assistant
|
|
44457
|
+
const relevantMessages = messages.filter((m2) => m2.info?.role === "assistant" || m2.info?.role === "tool");
|
|
44458
|
+
if (relevantMessages.length === 0) {
|
|
44459
|
+
log(`[call_omo_agent] No assistant or tool messages found`);
|
|
44415
44460
|
log(`[call_omo_agent] All messages:`, JSON.stringify(messages, null, 2));
|
|
44416
|
-
return `Error: No assistant response found
|
|
44461
|
+
return `Error: No assistant or tool response found
|
|
44417
44462
|
|
|
44418
44463
|
<task_metadata>
|
|
44419
44464
|
session_id: ${sessionID}
|
|
44420
44465
|
</task_metadata>`;
|
|
44421
44466
|
}
|
|
44422
|
-
log(`[call_omo_agent] Found
|
|
44423
|
-
const
|
|
44424
|
-
|
|
44467
|
+
log(`[call_omo_agent] Found ${relevantMessages.length} relevant messages`);
|
|
44468
|
+
const sortedMessages = [...relevantMessages].sort((a, b3) => {
|
|
44469
|
+
const timeA = a.info?.time?.created ?? 0;
|
|
44470
|
+
const timeB = b3.info?.time?.created ?? 0;
|
|
44471
|
+
return timeA - timeB;
|
|
44472
|
+
});
|
|
44473
|
+
const extractedContent = [];
|
|
44474
|
+
for (const message of sortedMessages) {
|
|
44475
|
+
for (const part of message.parts ?? []) {
|
|
44476
|
+
if ((part.type === "text" || part.type === "reasoning") && part.text) {
|
|
44477
|
+
extractedContent.push(part.text);
|
|
44478
|
+
} else if (part.type === "tool_result") {
|
|
44479
|
+
const toolResult = part;
|
|
44480
|
+
if (typeof toolResult.content === "string" && toolResult.content) {
|
|
44481
|
+
extractedContent.push(toolResult.content);
|
|
44482
|
+
} else if (Array.isArray(toolResult.content)) {
|
|
44483
|
+
for (const block of toolResult.content) {
|
|
44484
|
+
if ((block.type === "text" || block.type === "reasoning") && block.text) {
|
|
44485
|
+
extractedContent.push(block.text);
|
|
44486
|
+
}
|
|
44487
|
+
}
|
|
44488
|
+
}
|
|
44489
|
+
}
|
|
44490
|
+
}
|
|
44491
|
+
}
|
|
44492
|
+
const responseText = extractedContent.filter((text) => text.length > 0).join(`
|
|
44493
|
+
|
|
44425
44494
|
`);
|
|
44426
44495
|
log(`[call_omo_agent] Got response, length: ${responseText.length}`);
|
|
44427
44496
|
const output = responseText + `
|
|
@@ -44856,6 +44925,29 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`;
|
|
|
44856
44925
|
|
|
44857
44926
|
Session ID: ${args.resume}`;
|
|
44858
44927
|
}
|
|
44928
|
+
const POLL_INTERVAL_MS = 500;
|
|
44929
|
+
const MIN_STABILITY_TIME_MS = 5000;
|
|
44930
|
+
const STABILITY_POLLS_REQUIRED = 3;
|
|
44931
|
+
const pollStart = Date.now();
|
|
44932
|
+
let lastMsgCount = 0;
|
|
44933
|
+
let stablePolls = 0;
|
|
44934
|
+
while (Date.now() - pollStart < 60000) {
|
|
44935
|
+
await new Promise((resolve8) => setTimeout(resolve8, POLL_INTERVAL_MS));
|
|
44936
|
+
const elapsed = Date.now() - pollStart;
|
|
44937
|
+
if (elapsed < MIN_STABILITY_TIME_MS)
|
|
44938
|
+
continue;
|
|
44939
|
+
const messagesCheck = await client2.session.messages({ path: { id: args.resume } });
|
|
44940
|
+
const msgs = messagesCheck.data ?? messagesCheck;
|
|
44941
|
+
const currentMsgCount = msgs.length;
|
|
44942
|
+
if (currentMsgCount > 0 && currentMsgCount === lastMsgCount) {
|
|
44943
|
+
stablePolls++;
|
|
44944
|
+
if (stablePolls >= STABILITY_POLLS_REQUIRED)
|
|
44945
|
+
break;
|
|
44946
|
+
} else {
|
|
44947
|
+
stablePolls = 0;
|
|
44948
|
+
lastMsgCount = currentMsgCount;
|
|
44949
|
+
}
|
|
44950
|
+
}
|
|
44859
44951
|
const messagesResult = await client2.session.messages({
|
|
44860
44952
|
path: { id: args.resume }
|
|
44861
44953
|
});
|
|
@@ -44878,7 +44970,7 @@ Session ID: ${args.resume}`;
|
|
|
44878
44970
|
|
|
44879
44971
|
Session ID: ${args.resume}`;
|
|
44880
44972
|
}
|
|
44881
|
-
const textParts = lastMessage?.parts?.filter((p2) => p2.type === "text") ?? [];
|
|
44973
|
+
const textParts = lastMessage?.parts?.filter((p2) => p2.type === "text" || p2.type === "reasoning") ?? [];
|
|
44882
44974
|
const textContent = textParts.map((p2) => p2.text ?? "").filter(Boolean).join(`
|
|
44883
44975
|
`);
|
|
44884
44976
|
const duration3 = formatDuration2(startTime);
|
|
@@ -44992,11 +45084,10 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id
|
|
|
44992
45084
|
metadata: { sessionId: sessionID, category: args.category, sync: true }
|
|
44993
45085
|
});
|
|
44994
45086
|
let promptError;
|
|
44995
|
-
|
|
45087
|
+
client2.session.prompt({
|
|
44996
45088
|
path: { id: sessionID },
|
|
44997
45089
|
body: {
|
|
44998
45090
|
agent: agentToUse,
|
|
44999
|
-
model: categoryModel,
|
|
45000
45091
|
system: systemContent,
|
|
45001
45092
|
tools: {
|
|
45002
45093
|
task: false,
|
|
@@ -45007,6 +45098,7 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id
|
|
|
45007
45098
|
}).catch((error45) => {
|
|
45008
45099
|
promptError = error45 instanceof Error ? error45 : new Error(String(error45));
|
|
45009
45100
|
});
|
|
45101
|
+
await new Promise((resolve8) => setTimeout(resolve8, 100));
|
|
45010
45102
|
if (promptError) {
|
|
45011
45103
|
if (toastManager && taskId !== undefined) {
|
|
45012
45104
|
toastManager.removeTask(taskId);
|
|
@@ -45023,14 +45115,51 @@ Session ID: ${sessionID}`;
|
|
|
45023
45115
|
}
|
|
45024
45116
|
const POLL_INTERVAL_MS = 500;
|
|
45025
45117
|
const MAX_POLL_TIME_MS = 10 * 60 * 1000;
|
|
45118
|
+
const MIN_STABILITY_TIME_MS = 1e4;
|
|
45119
|
+
const STABILITY_POLLS_REQUIRED = 3;
|
|
45026
45120
|
const pollStart = Date.now();
|
|
45121
|
+
let lastMsgCount = 0;
|
|
45122
|
+
let stablePolls = 0;
|
|
45027
45123
|
while (Date.now() - pollStart < MAX_POLL_TIME_MS) {
|
|
45028
45124
|
await new Promise((resolve8) => setTimeout(resolve8, POLL_INTERVAL_MS));
|
|
45125
|
+
const asyncError = promptError;
|
|
45126
|
+
if (asyncError) {
|
|
45127
|
+
if (toastManager && taskId !== undefined) {
|
|
45128
|
+
toastManager.removeTask(taskId);
|
|
45129
|
+
}
|
|
45130
|
+
const errorMessage = asyncError.message;
|
|
45131
|
+
if (errorMessage.includes("agent.name") || errorMessage.includes("undefined")) {
|
|
45132
|
+
return `\u274C Agent "${agentToUse}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.
|
|
45133
|
+
|
|
45134
|
+
Session ID: ${sessionID}`;
|
|
45135
|
+
}
|
|
45136
|
+
return `\u274C Failed to send prompt: ${errorMessage}
|
|
45137
|
+
|
|
45138
|
+
Session ID: ${sessionID}`;
|
|
45139
|
+
}
|
|
45029
45140
|
const statusResult = await client2.session.status();
|
|
45030
45141
|
const allStatuses = statusResult.data ?? {};
|
|
45031
45142
|
const sessionStatus = allStatuses[sessionID];
|
|
45032
|
-
if (
|
|
45033
|
-
|
|
45143
|
+
if (sessionStatus && sessionStatus.type !== "idle") {
|
|
45144
|
+
stablePolls = 0;
|
|
45145
|
+
lastMsgCount = 0;
|
|
45146
|
+
continue;
|
|
45147
|
+
}
|
|
45148
|
+
const elapsed = Date.now() - pollStart;
|
|
45149
|
+
if (elapsed < MIN_STABILITY_TIME_MS) {
|
|
45150
|
+
continue;
|
|
45151
|
+
}
|
|
45152
|
+
const messagesCheck = await client2.session.messages({ path: { id: sessionID } });
|
|
45153
|
+
const msgs = messagesCheck.data ?? messagesCheck;
|
|
45154
|
+
const currentMsgCount = msgs.length;
|
|
45155
|
+
if (currentMsgCount > 0 && currentMsgCount === lastMsgCount) {
|
|
45156
|
+
stablePolls++;
|
|
45157
|
+
if (stablePolls >= STABILITY_POLLS_REQUIRED) {
|
|
45158
|
+
break;
|
|
45159
|
+
}
|
|
45160
|
+
} else {
|
|
45161
|
+
stablePolls = 0;
|
|
45162
|
+
lastMsgCount = currentMsgCount;
|
|
45034
45163
|
}
|
|
45035
45164
|
}
|
|
45036
45165
|
const messagesResult = await client2.session.messages({
|
|
@@ -45049,7 +45178,7 @@ Session ID: ${sessionID}`;
|
|
|
45049
45178
|
|
|
45050
45179
|
Session ID: ${sessionID}`;
|
|
45051
45180
|
}
|
|
45052
|
-
const textParts = lastMessage?.parts?.filter((p2) => p2.type === "text") ?? [];
|
|
45181
|
+
const textParts = lastMessage?.parts?.filter((p2) => p2.type === "text" || p2.type === "reasoning") ?? [];
|
|
45053
45182
|
const textContent = textParts.map((p2) => p2.text ?? "").filter(Boolean).join(`
|
|
45054
45183
|
`);
|
|
45055
45184
|
const duration3 = formatDuration2(startTime);
|
|
@@ -45171,10 +45300,12 @@ class ConcurrencyManager {
|
|
|
45171
45300
|
|
|
45172
45301
|
// src/features/background-agent/manager.ts
|
|
45173
45302
|
var TASK_TTL_MS = 30 * 60 * 1000;
|
|
45303
|
+
var MIN_STABILITY_TIME_MS = 10 * 1000;
|
|
45174
45304
|
|
|
45175
45305
|
class BackgroundManager {
|
|
45176
45306
|
tasks;
|
|
45177
45307
|
notifications;
|
|
45308
|
+
pendingByParent;
|
|
45178
45309
|
client;
|
|
45179
45310
|
directory;
|
|
45180
45311
|
pollingInterval;
|
|
@@ -45182,11 +45313,18 @@ class BackgroundManager {
|
|
|
45182
45313
|
constructor(ctx, config3) {
|
|
45183
45314
|
this.tasks = new Map;
|
|
45184
45315
|
this.notifications = new Map;
|
|
45316
|
+
this.pendingByParent = new Map;
|
|
45185
45317
|
this.client = ctx.client;
|
|
45186
45318
|
this.directory = ctx.directory;
|
|
45187
45319
|
this.concurrencyManager = new ConcurrencyManager(config3);
|
|
45188
45320
|
}
|
|
45189
45321
|
async launch(input) {
|
|
45322
|
+
log("[background-agent] launch() called with:", {
|
|
45323
|
+
agent: input.agent,
|
|
45324
|
+
model: input.model,
|
|
45325
|
+
description: input.description,
|
|
45326
|
+
parentSessionID: input.parentSessionID
|
|
45327
|
+
});
|
|
45190
45328
|
if (!input.agent || input.agent.trim() === "") {
|
|
45191
45329
|
throw new Error("Agent parameter is required");
|
|
45192
45330
|
}
|
|
@@ -45228,6 +45366,9 @@ class BackgroundManager {
|
|
|
45228
45366
|
};
|
|
45229
45367
|
this.tasks.set(task.id, task);
|
|
45230
45368
|
this.startPolling();
|
|
45369
|
+
const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set;
|
|
45370
|
+
pending.add(task.id);
|
|
45371
|
+
this.pendingByParent.set(input.parentSessionID, pending);
|
|
45231
45372
|
log("[background-agent] Launching task:", { taskId: task.id, sessionID, agent: input.agent });
|
|
45232
45373
|
const toastManager = getTaskToastManager();
|
|
45233
45374
|
if (toastManager) {
|
|
@@ -45239,10 +45380,18 @@ class BackgroundManager {
|
|
|
45239
45380
|
skills: input.skills
|
|
45240
45381
|
});
|
|
45241
45382
|
}
|
|
45242
|
-
|
|
45383
|
+
log("[background-agent] Calling prompt (fire-and-forget) for launch with:", {
|
|
45384
|
+
sessionID,
|
|
45385
|
+
agent: input.agent,
|
|
45386
|
+
model: input.model,
|
|
45387
|
+
hasSkillContent: !!input.skillContent,
|
|
45388
|
+
promptLength: input.prompt.length
|
|
45389
|
+
});
|
|
45390
|
+
this.client.session.prompt({
|
|
45243
45391
|
path: { id: sessionID },
|
|
45244
45392
|
body: {
|
|
45245
45393
|
agent: input.agent,
|
|
45394
|
+
...input.model ? { model: input.model } : {},
|
|
45246
45395
|
system: input.skillContent,
|
|
45247
45396
|
tools: {
|
|
45248
45397
|
task: false,
|
|
@@ -45266,7 +45415,9 @@ class BackgroundManager {
|
|
|
45266
45415
|
this.concurrencyManager.release(existingTask.concurrencyKey);
|
|
45267
45416
|
}
|
|
45268
45417
|
this.markForNotification(existingTask);
|
|
45269
|
-
this.notifyParentSession(existingTask)
|
|
45418
|
+
this.notifyParentSession(existingTask).catch((err) => {
|
|
45419
|
+
log("[background-agent] Failed to notify on error:", err);
|
|
45420
|
+
});
|
|
45270
45421
|
}
|
|
45271
45422
|
});
|
|
45272
45423
|
return task;
|
|
@@ -45315,11 +45466,15 @@ class BackgroundManager {
|
|
|
45315
45466
|
progress: {
|
|
45316
45467
|
toolCalls: 0,
|
|
45317
45468
|
lastUpdate: new Date
|
|
45318
|
-
}
|
|
45469
|
+
},
|
|
45470
|
+
parentAgent: input.parentAgent
|
|
45319
45471
|
};
|
|
45320
45472
|
this.tasks.set(task.id, task);
|
|
45321
45473
|
subagentSessions.add(input.sessionID);
|
|
45322
45474
|
this.startPolling();
|
|
45475
|
+
const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set;
|
|
45476
|
+
pending.add(task.id);
|
|
45477
|
+
this.pendingByParent.set(input.parentSessionID, pending);
|
|
45323
45478
|
log("[background-agent] Registered external task:", { taskId: task.id, sessionID: input.sessionID });
|
|
45324
45479
|
return task;
|
|
45325
45480
|
}
|
|
@@ -45341,6 +45496,9 @@ class BackgroundManager {
|
|
|
45341
45496
|
};
|
|
45342
45497
|
this.startPolling();
|
|
45343
45498
|
subagentSessions.add(existingTask.sessionID);
|
|
45499
|
+
const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set;
|
|
45500
|
+
pending.add(existingTask.id);
|
|
45501
|
+
this.pendingByParent.set(input.parentSessionID, pending);
|
|
45344
45502
|
const toastManager = getTaskToastManager();
|
|
45345
45503
|
if (toastManager) {
|
|
45346
45504
|
toastManager.addTask({
|
|
@@ -45351,7 +45509,12 @@ class BackgroundManager {
|
|
|
45351
45509
|
});
|
|
45352
45510
|
}
|
|
45353
45511
|
log("[background-agent] Resuming task:", { taskId: existingTask.id, sessionID: existingTask.sessionID });
|
|
45354
|
-
|
|
45512
|
+
log("[background-agent] Resuming task - calling prompt (fire-and-forget) with:", {
|
|
45513
|
+
sessionID: existingTask.sessionID,
|
|
45514
|
+
agent: existingTask.agent,
|
|
45515
|
+
promptLength: input.prompt.length
|
|
45516
|
+
});
|
|
45517
|
+
this.client.session.prompt({
|
|
45355
45518
|
path: { id: existingTask.sessionID },
|
|
45356
45519
|
body: {
|
|
45357
45520
|
agent: existingTask.agent,
|
|
@@ -45362,13 +45525,15 @@ class BackgroundManager {
|
|
|
45362
45525
|
parts: [{ type: "text", text: input.prompt }]
|
|
45363
45526
|
}
|
|
45364
45527
|
}).catch((error45) => {
|
|
45365
|
-
log("[background-agent] resume
|
|
45528
|
+
log("[background-agent] resume prompt error:", error45);
|
|
45366
45529
|
existingTask.status = "error";
|
|
45367
45530
|
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
45368
45531
|
existingTask.error = errorMessage;
|
|
45369
45532
|
existingTask.completedAt = new Date;
|
|
45370
45533
|
this.markForNotification(existingTask);
|
|
45371
|
-
this.notifyParentSession(existingTask)
|
|
45534
|
+
this.notifyParentSession(existingTask).catch((err) => {
|
|
45535
|
+
log("[background-agent] Failed to notify on resume error:", err);
|
|
45536
|
+
});
|
|
45372
45537
|
});
|
|
45373
45538
|
return existingTask;
|
|
45374
45539
|
}
|
|
@@ -45417,7 +45582,18 @@ class BackgroundManager {
|
|
|
45417
45582
|
const task = this.findBySession(sessionID);
|
|
45418
45583
|
if (!task || task.status !== "running")
|
|
45419
45584
|
return;
|
|
45420
|
-
|
|
45585
|
+
const elapsedMs = Date.now() - task.startedAt.getTime();
|
|
45586
|
+
const MIN_IDLE_TIME_MS = 5000;
|
|
45587
|
+
if (elapsedMs < MIN_IDLE_TIME_MS) {
|
|
45588
|
+
log("[background-agent] Ignoring early session.idle, elapsed:", { elapsedMs, taskId: task.id });
|
|
45589
|
+
return;
|
|
45590
|
+
}
|
|
45591
|
+
this.validateSessionHasOutput(sessionID).then(async (hasValidOutput) => {
|
|
45592
|
+
if (!hasValidOutput) {
|
|
45593
|
+
log("[background-agent] Session.idle but no valid output yet, waiting:", task.id);
|
|
45594
|
+
return;
|
|
45595
|
+
}
|
|
45596
|
+
const hasIncompleteTodos2 = await this.checkSessionTodos(sessionID);
|
|
45421
45597
|
if (hasIncompleteTodos2) {
|
|
45422
45598
|
log("[background-agent] Task has incomplete todos, waiting for todo-continuation:", task.id);
|
|
45423
45599
|
return;
|
|
@@ -45425,8 +45601,10 @@ class BackgroundManager {
|
|
|
45425
45601
|
task.status = "completed";
|
|
45426
45602
|
task.completedAt = new Date;
|
|
45427
45603
|
this.markForNotification(task);
|
|
45428
|
-
this.notifyParentSession(task);
|
|
45604
|
+
await this.notifyParentSession(task);
|
|
45429
45605
|
log("[background-agent] Task completed via session.idle event:", task.id);
|
|
45606
|
+
}).catch((err) => {
|
|
45607
|
+
log("[background-agent] Error in session.idle handler:", err);
|
|
45430
45608
|
});
|
|
45431
45609
|
}
|
|
45432
45610
|
if (event.type === "session.deleted") {
|
|
@@ -45461,6 +45639,33 @@ class BackgroundManager {
|
|
|
45461
45639
|
clearNotifications(sessionID) {
|
|
45462
45640
|
this.notifications.delete(sessionID);
|
|
45463
45641
|
}
|
|
45642
|
+
async validateSessionHasOutput(sessionID) {
|
|
45643
|
+
try {
|
|
45644
|
+
const response2 = await this.client.session.messages({
|
|
45645
|
+
path: { id: sessionID }
|
|
45646
|
+
});
|
|
45647
|
+
const messages = response2.data ?? [];
|
|
45648
|
+
const hasAssistantOrToolMessage = messages.some((m2) => m2.info?.role === "assistant" || m2.info?.role === "tool");
|
|
45649
|
+
if (!hasAssistantOrToolMessage) {
|
|
45650
|
+
log("[background-agent] No assistant/tool messages found in session:", sessionID);
|
|
45651
|
+
return false;
|
|
45652
|
+
}
|
|
45653
|
+
const hasContent2 = messages.some((m2) => {
|
|
45654
|
+
if (m2.info?.role !== "assistant" && m2.info?.role !== "tool")
|
|
45655
|
+
return false;
|
|
45656
|
+
const parts = m2.parts ?? [];
|
|
45657
|
+
return parts.some((p2) => p2.type === "text" && p2.text && p2.text.trim().length > 0 || p2.type === "reasoning" && p2.text && p2.text.trim().length > 0 || p2.type === "tool" || p2.type === "tool_result" && p2.content && (typeof p2.content === "string" ? p2.content.trim().length > 0 : p2.content.length > 0));
|
|
45658
|
+
});
|
|
45659
|
+
if (!hasContent2) {
|
|
45660
|
+
log("[background-agent] Messages exist but no content found in session:", sessionID);
|
|
45661
|
+
return false;
|
|
45662
|
+
}
|
|
45663
|
+
return true;
|
|
45664
|
+
} catch (error45) {
|
|
45665
|
+
log("[background-agent] Error validating session output:", error45);
|
|
45666
|
+
return true;
|
|
45667
|
+
}
|
|
45668
|
+
}
|
|
45464
45669
|
clearNotificationsForTask(taskId) {
|
|
45465
45670
|
for (const [sessionID, tasks] of this.notifications.entries()) {
|
|
45466
45671
|
const filtered = tasks.filter((t) => t.id !== taskId);
|
|
@@ -45489,8 +45694,15 @@ class BackgroundManager {
|
|
|
45489
45694
|
this.stopPolling();
|
|
45490
45695
|
this.tasks.clear();
|
|
45491
45696
|
this.notifications.clear();
|
|
45697
|
+
this.pendingByParent.clear();
|
|
45698
|
+
}
|
|
45699
|
+
getRunningTasks() {
|
|
45700
|
+
return Array.from(this.tasks.values()).filter((t) => t.status === "running");
|
|
45492
45701
|
}
|
|
45493
|
-
|
|
45702
|
+
getCompletedTasks() {
|
|
45703
|
+
return Array.from(this.tasks.values()).filter((t) => t.status !== "running");
|
|
45704
|
+
}
|
|
45705
|
+
async notifyParentSession(task) {
|
|
45494
45706
|
const duration3 = this.formatDuration(task.startedAt, task.completedAt);
|
|
45495
45707
|
log("[background-agent] notifyParentSession called for task:", task.id);
|
|
45496
45708
|
const toastManager = getTaskToastManager();
|
|
@@ -45501,33 +45713,70 @@ class BackgroundManager {
|
|
|
45501
45713
|
duration: duration3
|
|
45502
45714
|
});
|
|
45503
45715
|
}
|
|
45504
|
-
const
|
|
45505
|
-
|
|
45716
|
+
const pendingSet = this.pendingByParent.get(task.parentSessionID);
|
|
45717
|
+
if (pendingSet) {
|
|
45718
|
+
pendingSet.delete(task.id);
|
|
45719
|
+
if (pendingSet.size === 0) {
|
|
45720
|
+
this.pendingByParent.delete(task.parentSessionID);
|
|
45721
|
+
}
|
|
45722
|
+
}
|
|
45723
|
+
const allComplete = !pendingSet || pendingSet.size === 0;
|
|
45724
|
+
const remainingCount = pendingSet?.size ?? 0;
|
|
45725
|
+
const statusText = task.status === "error" ? "FAILED" : "COMPLETED";
|
|
45726
|
+
const errorInfo = task.error ? `
|
|
45727
|
+
**Error:** ${task.error}` : "";
|
|
45728
|
+
let notification;
|
|
45729
|
+
if (allComplete) {
|
|
45730
|
+
const completedTasks = Array.from(this.tasks.values()).filter((t) => t.parentSessionID === task.parentSessionID && t.status !== "running").map((t) => `- \`${t.id}\`: ${t.description}`).join(`
|
|
45731
|
+
`);
|
|
45732
|
+
notification = `<system-reminder>
|
|
45733
|
+
[ALL BACKGROUND TASKS COMPLETE]
|
|
45734
|
+
|
|
45735
|
+
**Completed:**
|
|
45736
|
+
${completedTasks || `- \`${task.id}\`: ${task.description}`}
|
|
45737
|
+
|
|
45738
|
+
Use \`background_output(task_id="<id>")\` to retrieve each result.
|
|
45739
|
+
</system-reminder>`;
|
|
45740
|
+
} else {
|
|
45741
|
+
notification = `<system-reminder>
|
|
45742
|
+
[BACKGROUND TASK ${statusText}]
|
|
45743
|
+
**ID:** \`${task.id}\`
|
|
45744
|
+
**Description:** ${task.description}
|
|
45745
|
+
**Duration:** ${duration3}${errorInfo}
|
|
45746
|
+
|
|
45747
|
+
**${remainingCount} task${remainingCount === 1 ? "" : "s"} still in progress.** You WILL be notified when ALL complete.
|
|
45748
|
+
Do NOT poll - continue productive work.
|
|
45749
|
+
|
|
45750
|
+
Use \`background_output(task_id="${task.id}")\` to retrieve this result when ready.
|
|
45751
|
+
</system-reminder>`;
|
|
45752
|
+
}
|
|
45753
|
+
try {
|
|
45754
|
+
await this.client.session.prompt({
|
|
45755
|
+
path: { id: task.parentSessionID },
|
|
45756
|
+
body: {
|
|
45757
|
+
noReply: !allComplete,
|
|
45758
|
+
agent: task.parentAgent,
|
|
45759
|
+
parts: [{ type: "text", text: notification }]
|
|
45760
|
+
}
|
|
45761
|
+
});
|
|
45762
|
+
log("[background-agent] Sent notification to parent session:", {
|
|
45763
|
+
taskId: task.id,
|
|
45764
|
+
allComplete,
|
|
45765
|
+
noReply: !allComplete
|
|
45766
|
+
});
|
|
45767
|
+
} catch (error45) {
|
|
45768
|
+
log("[background-agent] Failed to send notification:", error45);
|
|
45769
|
+
}
|
|
45506
45770
|
const taskId = task.id;
|
|
45507
|
-
setTimeout(
|
|
45771
|
+
setTimeout(() => {
|
|
45508
45772
|
if (task.concurrencyKey) {
|
|
45509
45773
|
this.concurrencyManager.release(task.concurrencyKey);
|
|
45774
|
+
task.concurrencyKey = undefined;
|
|
45510
45775
|
}
|
|
45511
|
-
|
|
45512
|
-
|
|
45513
|
-
|
|
45514
|
-
|
|
45515
|
-
body: {
|
|
45516
|
-
agent: task.parentAgent,
|
|
45517
|
-
model: modelField,
|
|
45518
|
-
parts: [{ type: "text", text: message }]
|
|
45519
|
-
},
|
|
45520
|
-
query: { directory: this.directory }
|
|
45521
|
-
});
|
|
45522
|
-
log("[background-agent] Successfully sent prompt to parent session:", { parentSessionID: task.parentSessionID });
|
|
45523
|
-
} catch (error45) {
|
|
45524
|
-
log("[background-agent] prompt failed:", String(error45));
|
|
45525
|
-
} finally {
|
|
45526
|
-
this.clearNotificationsForTask(taskId);
|
|
45527
|
-
this.tasks.delete(taskId);
|
|
45528
|
-
log("[background-agent] Removed completed task from memory:", taskId);
|
|
45529
|
-
}
|
|
45530
|
-
}, 200);
|
|
45776
|
+
this.clearNotificationsForTask(taskId);
|
|
45777
|
+
this.tasks.delete(taskId);
|
|
45778
|
+
log("[background-agent] Removed completed task from memory:", taskId);
|
|
45779
|
+
}, 5 * 60 * 1000);
|
|
45531
45780
|
}
|
|
45532
45781
|
formatDuration(start, end) {
|
|
45533
45782
|
const duration3 = (end ?? new Date).getTime() - start.getTime();
|
|
@@ -45590,11 +45839,12 @@ class BackgroundManager {
|
|
|
45590
45839
|
continue;
|
|
45591
45840
|
try {
|
|
45592
45841
|
const sessionStatus = allStatuses[task.sessionID];
|
|
45593
|
-
if (
|
|
45594
|
-
|
|
45595
|
-
|
|
45596
|
-
|
|
45597
|
-
|
|
45842
|
+
if (sessionStatus?.type === "idle") {
|
|
45843
|
+
const hasValidOutput = await this.validateSessionHasOutput(task.sessionID);
|
|
45844
|
+
if (!hasValidOutput) {
|
|
45845
|
+
log("[background-agent] Polling idle but no valid output yet, waiting:", task.id);
|
|
45846
|
+
continue;
|
|
45847
|
+
}
|
|
45598
45848
|
const hasIncompleteTodos2 = await this.checkSessionTodos(task.sessionID);
|
|
45599
45849
|
if (hasIncompleteTodos2) {
|
|
45600
45850
|
log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
|
|
@@ -45603,7 +45853,7 @@ class BackgroundManager {
|
|
|
45603
45853
|
task.status = "completed";
|
|
45604
45854
|
task.completedAt = new Date;
|
|
45605
45855
|
this.markForNotification(task);
|
|
45606
|
-
this.notifyParentSession(task);
|
|
45856
|
+
await this.notifyParentSession(task);
|
|
45607
45857
|
log("[background-agent] Task completed via polling:", task.id);
|
|
45608
45858
|
continue;
|
|
45609
45859
|
}
|
|
@@ -45638,6 +45888,32 @@ class BackgroundManager {
|
|
|
45638
45888
|
task.progress.lastMessage = lastMessage;
|
|
45639
45889
|
task.progress.lastMessageAt = new Date;
|
|
45640
45890
|
}
|
|
45891
|
+
const currentMsgCount = messages.length;
|
|
45892
|
+
const elapsedMs = Date.now() - task.startedAt.getTime();
|
|
45893
|
+
if (elapsedMs >= MIN_STABILITY_TIME_MS) {
|
|
45894
|
+
if (task.lastMsgCount === currentMsgCount) {
|
|
45895
|
+
task.stablePolls = (task.stablePolls ?? 0) + 1;
|
|
45896
|
+
if (task.stablePolls >= 3) {
|
|
45897
|
+
const hasValidOutput = await this.validateSessionHasOutput(task.sessionID);
|
|
45898
|
+
if (!hasValidOutput) {
|
|
45899
|
+
log("[background-agent] Stability reached but no valid output, waiting:", task.id);
|
|
45900
|
+
continue;
|
|
45901
|
+
}
|
|
45902
|
+
const hasIncompleteTodos2 = await this.checkSessionTodos(task.sessionID);
|
|
45903
|
+
if (!hasIncompleteTodos2) {
|
|
45904
|
+
task.status = "completed";
|
|
45905
|
+
task.completedAt = new Date;
|
|
45906
|
+
this.markForNotification(task);
|
|
45907
|
+
await this.notifyParentSession(task);
|
|
45908
|
+
log("[background-agent] Task completed via stability detection:", task.id);
|
|
45909
|
+
continue;
|
|
45910
|
+
}
|
|
45911
|
+
}
|
|
45912
|
+
} else {
|
|
45913
|
+
task.stablePolls = 0;
|
|
45914
|
+
}
|
|
45915
|
+
}
|
|
45916
|
+
task.lastMsgCount = currentMsgCount;
|
|
45641
45917
|
}
|
|
45642
45918
|
} catch (error45) {
|
|
45643
45919
|
log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
|
|
@@ -48454,7 +48730,9 @@ var BuiltinAgentNameSchema = exports_external.enum([
|
|
|
48454
48730
|
"frontend-ui-ux-engineer",
|
|
48455
48731
|
"document-writer",
|
|
48456
48732
|
"multimodal-looker",
|
|
48457
|
-
"Metis (Plan Consultant)"
|
|
48733
|
+
"Metis (Plan Consultant)",
|
|
48734
|
+
"Momus (Plan Reviewer)",
|
|
48735
|
+
"orchestrator-sisyphus"
|
|
48458
48736
|
]);
|
|
48459
48737
|
var BuiltinSkillNameSchema = exports_external.enum([
|
|
48460
48738
|
"playwright",
|
|
@@ -48468,12 +48746,14 @@ var OverridableAgentNameSchema = exports_external.enum([
|
|
|
48468
48746
|
"OpenCode-Builder",
|
|
48469
48747
|
"Prometheus (Planner)",
|
|
48470
48748
|
"Metis (Plan Consultant)",
|
|
48749
|
+
"Momus (Plan Reviewer)",
|
|
48471
48750
|
"oracle",
|
|
48472
48751
|
"librarian",
|
|
48473
48752
|
"explore",
|
|
48474
48753
|
"frontend-ui-ux-engineer",
|
|
48475
48754
|
"document-writer",
|
|
48476
|
-
"multimodal-looker"
|
|
48755
|
+
"multimodal-looker",
|
|
48756
|
+
"orchestrator-sisyphus"
|
|
48477
48757
|
]);
|
|
48478
48758
|
var HookNameSchema = exports_external.enum([
|
|
48479
48759
|
"todo-continuation-enforcer",
|
|
@@ -48534,12 +48814,14 @@ var AgentOverridesSchema = exports_external.object({
|
|
|
48534
48814
|
"OpenCode-Builder": AgentOverrideConfigSchema.optional(),
|
|
48535
48815
|
"Prometheus (Planner)": AgentOverrideConfigSchema.optional(),
|
|
48536
48816
|
"Metis (Plan Consultant)": AgentOverrideConfigSchema.optional(),
|
|
48817
|
+
"Momus (Plan Reviewer)": AgentOverrideConfigSchema.optional(),
|
|
48537
48818
|
oracle: AgentOverrideConfigSchema.optional(),
|
|
48538
48819
|
librarian: AgentOverrideConfigSchema.optional(),
|
|
48539
48820
|
explore: AgentOverrideConfigSchema.optional(),
|
|
48540
48821
|
"frontend-ui-ux-engineer": AgentOverrideConfigSchema.optional(),
|
|
48541
48822
|
"document-writer": AgentOverrideConfigSchema.optional(),
|
|
48542
|
-
"multimodal-looker": AgentOverrideConfigSchema.optional()
|
|
48823
|
+
"multimodal-looker": AgentOverrideConfigSchema.optional(),
|
|
48824
|
+
"orchestrator-sisyphus": AgentOverrideConfigSchema.optional()
|
|
48543
48825
|
});
|
|
48544
48826
|
var ClaudeCodeConfigSchema = exports_external.object({
|
|
48545
48827
|
mcp: exports_external.boolean().optional(),
|
|
@@ -49056,7 +49338,6 @@ ${patterns.join(`
|
|
|
49056
49338
|
var DEFAULT_MODEL = "anthropic/claude-opus-4-5";
|
|
49057
49339
|
var SISYPHUS_ROLE_SECTION = `<Role>
|
|
49058
49340
|
You are "Sisyphus" - Powerful AI Agent with orchestration capabilities from OhMyOpenCode.
|
|
49059
|
-
Named by [YeonGyu Kim](https://github.com/code-yeongyu).
|
|
49060
49341
|
|
|
49061
49342
|
**Why Sisyphus?**: Humans roll their boulder every day. So do you. We're not so different\u2014your code should be indistinguishable from a senior engineer's.
|
|
49062
49343
|
|
|
@@ -49777,24 +50058,17 @@ var LIBRARIAN_PROMPT_METADATA = {
|
|
|
49777
50058
|
]
|
|
49778
50059
|
};
|
|
49779
50060
|
function createLibrarianAgent(model = DEFAULT_MODEL3) {
|
|
49780
|
-
const restrictions = createAgentToolRestrictions([
|
|
49781
|
-
"write",
|
|
49782
|
-
"edit",
|
|
49783
|
-
"task",
|
|
49784
|
-
"sisyphus_task",
|
|
49785
|
-
"call_omo_agent"
|
|
49786
|
-
]);
|
|
49787
50061
|
return {
|
|
49788
50062
|
description: "Specialized codebase understanding agent for multi-repository analysis, searching remote codebases, retrieving official documentation, and finding implementation examples using GitHub CLI, Context7, and Web Search. MUST BE USED when users ask to look up code in remote repositories, explain library internals, or find usage examples in open source.",
|
|
49789
50063
|
mode: "subagent",
|
|
49790
50064
|
model,
|
|
49791
50065
|
temperature: 0.1,
|
|
49792
|
-
|
|
50066
|
+
tools: { write: false, edit: false, background_task: false },
|
|
49793
50067
|
prompt: `# THE LIBRARIAN
|
|
49794
50068
|
|
|
49795
50069
|
You are **THE LIBRARIAN**, a specialized open-source codebase understanding agent.
|
|
49796
50070
|
|
|
49797
|
-
Your job: Answer questions about open-source libraries
|
|
50071
|
+
Your job: Answer questions about open-source libraries by finding **EVIDENCE** with **GitHub permalinks**.
|
|
49798
50072
|
|
|
49799
50073
|
## CRITICAL: DATE AWARENESS
|
|
49800
50074
|
|
|
@@ -49806,20 +50080,64 @@ Your job: Answer questions about open-source libraries. Provide **EVIDENCE** wit
|
|
|
49806
50080
|
|
|
49807
50081
|
---
|
|
49808
50082
|
|
|
49809
|
-
## PHASE 0:
|
|
49810
|
-
|
|
49811
|
-
**First**: Can you answer confidently from training knowledge? If yes, answer directly.
|
|
50083
|
+
## PHASE 0: REQUEST CLASSIFICATION (MANDATORY FIRST STEP)
|
|
49812
50084
|
|
|
49813
|
-
|
|
49814
|
-
|
|
49815
|
-
**If search needed**, classify into:
|
|
50085
|
+
Classify EVERY request into one of these categories before taking action:
|
|
49816
50086
|
|
|
49817
50087
|
| Type | Trigger Examples | Tools |
|
|
49818
50088
|
|------|------------------|-------|
|
|
49819
|
-
| **TYPE A: CONCEPTUAL** | "How do I use X?", "Best practice for Y?" |
|
|
50089
|
+
| **TYPE A: CONCEPTUAL** | "How do I use X?", "Best practice for Y?" | Doc Discovery \u2192 context7 + websearch |
|
|
49820
50090
|
| **TYPE B: IMPLEMENTATION** | "How does X implement Y?", "Show me source of Z" | gh clone + read + blame |
|
|
49821
|
-
| **TYPE C: CONTEXT** | "Why was this changed?", "
|
|
49822
|
-
| **TYPE D: COMPREHENSIVE** | Complex/ambiguous requests |
|
|
50091
|
+
| **TYPE C: CONTEXT** | "Why was this changed?", "History of X?" | gh issues/prs + git log/blame |
|
|
50092
|
+
| **TYPE D: COMPREHENSIVE** | Complex/ambiguous requests | Doc Discovery \u2192 ALL tools |
|
|
50093
|
+
|
|
50094
|
+
---
|
|
50095
|
+
|
|
50096
|
+
## PHASE 0.5: DOCUMENTATION DISCOVERY (FOR TYPE A & D)
|
|
50097
|
+
|
|
50098
|
+
**When to execute**: Before TYPE A or TYPE D investigations involving external libraries/frameworks.
|
|
50099
|
+
|
|
50100
|
+
### Step 1: Find Official Documentation
|
|
50101
|
+
\`\`\`
|
|
50102
|
+
websearch("library-name official documentation site")
|
|
50103
|
+
\`\`\`
|
|
50104
|
+
- Identify the **official documentation URL** (not blogs, not tutorials)
|
|
50105
|
+
- Note the base URL (e.g., \`https://docs.example.com\`)
|
|
50106
|
+
|
|
50107
|
+
### Step 2: Version Check (if version specified)
|
|
50108
|
+
If user mentions a specific version (e.g., "React 18", "Next.js 14", "v2.x"):
|
|
50109
|
+
\`\`\`
|
|
50110
|
+
websearch("library-name v{version} documentation")
|
|
50111
|
+
// OR check if docs have version selector:
|
|
50112
|
+
webfetch(official_docs_url + "/versions")
|
|
50113
|
+
// or
|
|
50114
|
+
webfetch(official_docs_url + "/v{version}")
|
|
50115
|
+
\`\`\`
|
|
50116
|
+
- Confirm you're looking at the **correct version's documentation**
|
|
50117
|
+
- Many docs have versioned URLs: \`/docs/v2/\`, \`/v14/\`, etc.
|
|
50118
|
+
|
|
50119
|
+
### Step 3: Sitemap Discovery (understand doc structure)
|
|
50120
|
+
\`\`\`
|
|
50121
|
+
webfetch(official_docs_base_url + "/sitemap.xml")
|
|
50122
|
+
// Fallback options:
|
|
50123
|
+
webfetch(official_docs_base_url + "/sitemap-0.xml")
|
|
50124
|
+
webfetch(official_docs_base_url + "/docs/sitemap.xml")
|
|
50125
|
+
\`\`\`
|
|
50126
|
+
- Parse sitemap to understand documentation structure
|
|
50127
|
+
- Identify relevant sections for the user's question
|
|
50128
|
+
- This prevents random searching\u2014you now know WHERE to look
|
|
50129
|
+
|
|
50130
|
+
### Step 4: Targeted Investigation
|
|
50131
|
+
With sitemap knowledge, fetch the SPECIFIC documentation pages relevant to the query:
|
|
50132
|
+
\`\`\`
|
|
50133
|
+
webfetch(specific_doc_page_from_sitemap)
|
|
50134
|
+
context7_query-docs(libraryId: id, query: "specific topic")
|
|
50135
|
+
\`\`\`
|
|
50136
|
+
|
|
50137
|
+
**Skip Doc Discovery when**:
|
|
50138
|
+
- TYPE B (implementation) - you're cloning repos anyway
|
|
50139
|
+
- TYPE C (context/history) - you're looking at issues/PRs
|
|
50140
|
+
- Library has no official docs (rare OSS projects)
|
|
49823
50141
|
|
|
49824
50142
|
---
|
|
49825
50143
|
|
|
@@ -49828,15 +50146,15 @@ Your job: Answer questions about open-source libraries. Provide **EVIDENCE** wit
|
|
|
49828
50146
|
### TYPE A: CONCEPTUAL QUESTION
|
|
49829
50147
|
**Trigger**: "How do I...", "What is...", "Best practice for...", rough/general questions
|
|
49830
50148
|
|
|
49831
|
-
**
|
|
50149
|
+
**Execute Documentation Discovery FIRST (Phase 0.5)**, then:
|
|
49832
50150
|
\`\`\`
|
|
49833
50151
|
Tool 1: context7_resolve-library-id("library-name")
|
|
49834
|
-
\u2192 then
|
|
49835
|
-
Tool 2:
|
|
49836
|
-
Tool 3 (
|
|
50152
|
+
\u2192 then context7_query-docs(libraryId: id, query: "specific-topic")
|
|
50153
|
+
Tool 2: webfetch(relevant_pages_from_sitemap) // Targeted, not random
|
|
50154
|
+
Tool 3: grep_app_searchGitHub(query: "usage pattern", language: ["TypeScript"])
|
|
49837
50155
|
\`\`\`
|
|
49838
50156
|
|
|
49839
|
-
**Output**: Summarize findings with links to official docs and real-world examples.
|
|
50157
|
+
**Output**: Summarize findings with links to official docs (versioned if applicable) and real-world examples.
|
|
49840
50158
|
|
|
49841
50159
|
---
|
|
49842
50160
|
|
|
@@ -49847,20 +50165,20 @@ Tool 3 (optional): If web search is available, search "library-name topic 2025"
|
|
|
49847
50165
|
\`\`\`
|
|
49848
50166
|
Step 1: Clone to temp directory
|
|
49849
50167
|
gh repo clone owner/repo \${TMPDIR:-/tmp}/repo-name -- --depth 1
|
|
49850
|
-
|
|
50168
|
+
|
|
49851
50169
|
Step 2: Get commit SHA for permalinks
|
|
49852
50170
|
cd \${TMPDIR:-/tmp}/repo-name && git rev-parse HEAD
|
|
49853
|
-
|
|
50171
|
+
|
|
49854
50172
|
Step 3: Find the implementation
|
|
49855
50173
|
- grep/ast_grep_search for function/class
|
|
49856
50174
|
- read the specific file
|
|
49857
50175
|
- git blame for context if needed
|
|
49858
|
-
|
|
50176
|
+
|
|
49859
50177
|
Step 4: Construct permalink
|
|
49860
50178
|
https://github.com/owner/repo/blob/<sha>/path/to/file#L10-L20
|
|
49861
50179
|
\`\`\`
|
|
49862
50180
|
|
|
49863
|
-
**
|
|
50181
|
+
**Parallel acceleration (4+ calls)**:
|
|
49864
50182
|
\`\`\`
|
|
49865
50183
|
Tool 1: gh repo clone owner/repo \${TMPDIR:-/tmp}/repo -- --depth 1
|
|
49866
50184
|
Tool 2: grep_app_searchGitHub(query: "function_name", repo: "owner/repo")
|
|
@@ -49873,7 +50191,7 @@ Tool 4: context7_get-library-docs(id, topic: "relevant-api")
|
|
|
49873
50191
|
### TYPE C: CONTEXT & HISTORY
|
|
49874
50192
|
**Trigger**: "Why was this changed?", "What's the history?", "Related issues/PRs?"
|
|
49875
50193
|
|
|
49876
|
-
**
|
|
50194
|
+
**Execute in parallel (4+ calls)**:
|
|
49877
50195
|
\`\`\`
|
|
49878
50196
|
Tool 1: gh search issues "keyword" --repo owner/repo --state all --limit 10
|
|
49879
50197
|
Tool 2: gh search prs "keyword" --repo owner/repo --state merged --limit 10
|
|
@@ -49895,22 +50213,21 @@ gh api repos/owner/repo/pulls/<number>/files
|
|
|
49895
50213
|
### TYPE D: COMPREHENSIVE RESEARCH
|
|
49896
50214
|
**Trigger**: Complex questions, ambiguous requests, "deep dive into..."
|
|
49897
50215
|
|
|
49898
|
-
**
|
|
50216
|
+
**Execute Documentation Discovery FIRST (Phase 0.5)**, then execute in parallel (6+ calls):
|
|
49899
50217
|
\`\`\`
|
|
49900
|
-
// Documentation
|
|
49901
|
-
Tool 1: context7_resolve-library-id \u2192
|
|
50218
|
+
// Documentation (informed by sitemap discovery)
|
|
50219
|
+
Tool 1: context7_resolve-library-id \u2192 context7_query-docs
|
|
50220
|
+
Tool 2: webfetch(targeted_doc_pages_from_sitemap)
|
|
49902
50221
|
|
|
49903
50222
|
// Code Search
|
|
49904
|
-
Tool
|
|
49905
|
-
Tool
|
|
50223
|
+
Tool 3: grep_app_searchGitHub(query: "pattern1", language: [...])
|
|
50224
|
+
Tool 4: grep_app_searchGitHub(query: "pattern2", useRegexp: true)
|
|
49906
50225
|
|
|
49907
50226
|
// Source Analysis
|
|
49908
|
-
Tool
|
|
50227
|
+
Tool 5: gh repo clone owner/repo \${TMPDIR:-/tmp}/repo -- --depth 1
|
|
49909
50228
|
|
|
49910
50229
|
// Context
|
|
49911
|
-
Tool
|
|
49912
|
-
|
|
49913
|
-
// Optional: If web search is available, search for recent updates
|
|
50230
|
+
Tool 6: gh search issues "topic" --repo owner/repo
|
|
49914
50231
|
\`\`\`
|
|
49915
50232
|
|
|
49916
50233
|
---
|
|
@@ -49955,7 +50272,11 @@ https://github.com/tanstack/query/blob/abc123def/packages/react-query/src/useQue
|
|
|
49955
50272
|
|
|
49956
50273
|
| Purpose | Tool | Command/Usage |
|
|
49957
50274
|
|---------|------|---------------|
|
|
49958
|
-
| **Official Docs** | context7 | \`context7_resolve-library-id\` \u2192 \`
|
|
50275
|
+
| **Official Docs** | context7 | \`context7_resolve-library-id\` \u2192 \`context7_query-docs\` |
|
|
50276
|
+
| **Find Docs URL** | websearch_exa | \`websearch_exa_web_search_exa("library official documentation")\` |
|
|
50277
|
+
| **Sitemap Discovery** | webfetch | \`webfetch(docs_url + "/sitemap.xml")\` to understand doc structure |
|
|
50278
|
+
| **Read Doc Page** | webfetch | \`webfetch(specific_doc_page)\` for targeted documentation |
|
|
50279
|
+
| **Latest Info** | websearch_exa | \`websearch_exa_web_search_exa("query 2025")\` |
|
|
49959
50280
|
| **Fast Code Search** | grep_app | \`grep_app_searchGitHub(query, language, useRegexp)\` |
|
|
49960
50281
|
| **Deep Code Search** | gh CLI | \`gh search code "query" --repo owner/repo\` |
|
|
49961
50282
|
| **Clone Repo** | gh CLI | \`gh repo clone owner/repo \${TMPDIR:-/tmp}/name -- --depth 1\` |
|
|
@@ -49963,8 +50284,6 @@ https://github.com/tanstack/query/blob/abc123def/packages/react-query/src/useQue
|
|
|
49963
50284
|
| **View Issue/PR** | gh CLI | \`gh issue/pr view <num> --repo owner/repo --comments\` |
|
|
49964
50285
|
| **Release Info** | gh CLI | \`gh api repos/owner/repo/releases/latest\` |
|
|
49965
50286
|
| **Git History** | git | \`git log\`, \`git blame\`, \`git show\` |
|
|
49966
|
-
| **Read URL** | webfetch | \`webfetch(url)\` for blog posts, SO threads |
|
|
49967
|
-
| **Web Search** | (if available) | Use any available web search tool for latest info |
|
|
49968
50287
|
|
|
49969
50288
|
### Temp Directory
|
|
49970
50289
|
|
|
@@ -49981,16 +50300,18 @@ Use OS-appropriate temp directory:
|
|
|
49981
50300
|
|
|
49982
50301
|
---
|
|
49983
50302
|
|
|
49984
|
-
## PARALLEL EXECUTION
|
|
50303
|
+
## PARALLEL EXECUTION REQUIREMENTS
|
|
49985
50304
|
|
|
49986
|
-
|
|
49987
|
-
|
|
49988
|
-
| Request Type | Suggested Calls |
|
|
50305
|
+
| Request Type | Suggested Calls | Doc Discovery Required |
|
|
49989
50306
|
|--------------|----------------|
|
|
49990
|
-
| TYPE A (Conceptual) | 1-2 |
|
|
49991
|
-
| TYPE B (Implementation) | 2-3 |
|
|
49992
|
-
| TYPE C (Context) | 2-3 |
|
|
49993
|
-
| TYPE D (Comprehensive) | 3-5 |
|
|
50307
|
+
| TYPE A (Conceptual) | 1-2 | YES (Phase 0.5 first) |
|
|
50308
|
+
| TYPE B (Implementation) | 2-3 NO |
|
|
50309
|
+
| TYPE C (Context) | 2-3 NO |
|
|
50310
|
+
| TYPE D (Comprehensive) | 3-5 | YES (Phase 0.5 first) |
|
|
50311
|
+
| Request Type | Minimum Parallel Calls
|
|
50312
|
+
|
|
50313
|
+
**Doc Discovery is SEQUENTIAL** (websearch \u2192 version check \u2192 sitemap \u2192 investigate).
|
|
50314
|
+
**Main phase is PARALLEL** once you know where to look.
|
|
49994
50315
|
|
|
49995
50316
|
**Always vary queries** when using grep_app:
|
|
49996
50317
|
\`\`\`
|
|
@@ -50014,6 +50335,8 @@ grep_app_searchGitHub(query: "useQuery")
|
|
|
50014
50335
|
| grep_app no results | Broaden query, try concept instead of exact name |
|
|
50015
50336
|
| gh API rate limit | Use cloned repo in temp directory |
|
|
50016
50337
|
| Repo not found | Search for forks or mirrors |
|
|
50338
|
+
| Sitemap not found | Try \`/sitemap-0.xml\`, \`/sitemap_index.xml\`, or fetch docs index page and parse navigation |
|
|
50339
|
+
| Versioned docs not found | Fall back to latest version, note this in response |
|
|
50017
50340
|
| Uncertain | **STATE YOUR UNCERTAINTY**, propose hypothesis |
|
|
50018
50341
|
|
|
50019
50342
|
---
|
|
@@ -50021,7 +50344,7 @@ grep_app_searchGitHub(query: "useQuery")
|
|
|
50021
50344
|
## COMMUNICATION RULES
|
|
50022
50345
|
|
|
50023
50346
|
1. **NO TOOL NAMES**: Say "I'll search the codebase" not "I'll use grep_app"
|
|
50024
|
-
2. **NO PREAMBLE**: Answer directly, skip "I'll help you with..."
|
|
50347
|
+
2. **NO PREAMBLE**: Answer directly, skip "I'll help you with..."
|
|
50025
50348
|
3. **ALWAYS CITE**: Every code claim needs a permalink
|
|
50026
50349
|
4. **USE MARKDOWN**: Code blocks with language identifiers
|
|
50027
50350
|
5. **BE CONCISE**: Facts > opinions, evidence > speculation
|
|
@@ -50781,15 +51104,19 @@ var metisRestrictions = createAgentToolRestrictions([
|
|
|
50781
51104
|
"task",
|
|
50782
51105
|
"sisyphus_task"
|
|
50783
51106
|
]);
|
|
50784
|
-
var
|
|
50785
|
-
|
|
50786
|
-
|
|
50787
|
-
|
|
50788
|
-
|
|
50789
|
-
|
|
50790
|
-
|
|
50791
|
-
|
|
50792
|
-
|
|
51107
|
+
var DEFAULT_MODEL8 = "anthropic/claude-opus-4-5";
|
|
51108
|
+
function createMetisAgent(model = DEFAULT_MODEL8) {
|
|
51109
|
+
return {
|
|
51110
|
+
description: "Pre-planning consultant that analyzes requests to identify hidden intentions, ambiguities, and AI failure points.",
|
|
51111
|
+
mode: "subagent",
|
|
51112
|
+
model,
|
|
51113
|
+
temperature: 0.3,
|
|
51114
|
+
...metisRestrictions,
|
|
51115
|
+
prompt: METIS_SYSTEM_PROMPT,
|
|
51116
|
+
thinking: { type: "enabled", budgetTokens: 32000 }
|
|
51117
|
+
};
|
|
51118
|
+
}
|
|
51119
|
+
var metisAgent = createMetisAgent();
|
|
50793
51120
|
|
|
50794
51121
|
// src/agents/orchestrator-sisyphus.ts
|
|
50795
51122
|
init_constants();
|
|
@@ -50903,7 +51230,6 @@ ${rows.join(`
|
|
|
50903
51230
|
**NEVER provide both category AND agent - they are mutually exclusive.**`;
|
|
50904
51231
|
}
|
|
50905
51232
|
var ORCHESTRATOR_SISYPHUS_SYSTEM_PROMPT = `You are "Sisyphus" - Powerful AI Agent with orchestration capabilities from OhMyOpenCode.
|
|
50906
|
-
Named by [YeonGyu Kim](https://github.com/code-yeongyu).
|
|
50907
51233
|
|
|
50908
51234
|
**Why Sisyphus?**: Humans roll their boulder every day. So do you. We're not so different\u2014your code should be indistinguishable from a senior engineer's.
|
|
50909
51235
|
|
|
@@ -52196,6 +52522,7 @@ function buildDynamicOrchestratorPrompt(ctx) {
|
|
|
52196
52522
|
const skillsSection = buildSkillsSection(skills);
|
|
52197
52523
|
return ORCHESTRATOR_SISYPHUS_SYSTEM_PROMPT.replace("{CATEGORY_SECTION}", categorySection).replace("{AGENT_SECTION}", agentSection).replace("{DECISION_MATRIX}", decisionMatrix).replace("{SKILLS_SECTION}", skillsSection);
|
|
52198
52524
|
}
|
|
52525
|
+
var DEFAULT_MODEL9 = "anthropic/claude-sonnet-4-5";
|
|
52199
52526
|
function createOrchestratorSisyphusAgent(ctx) {
|
|
52200
52527
|
const restrictions = createAgentToolRestrictions([
|
|
52201
52528
|
"task",
|
|
@@ -52204,7 +52531,7 @@ function createOrchestratorSisyphusAgent(ctx) {
|
|
|
52204
52531
|
return {
|
|
52205
52532
|
description: "Orchestrates work via sisyphus_task() to complete ALL tasks in a todo list until fully done",
|
|
52206
52533
|
mode: "primary",
|
|
52207
|
-
model:
|
|
52534
|
+
model: ctx?.model ?? DEFAULT_MODEL9,
|
|
52208
52535
|
temperature: 0.1,
|
|
52209
52536
|
prompt: buildDynamicOrchestratorPrompt(ctx),
|
|
52210
52537
|
thinking: { type: "enabled", budgetTokens: 32000 },
|
|
@@ -52214,7 +52541,7 @@ function createOrchestratorSisyphusAgent(ctx) {
|
|
|
52214
52541
|
var orchestratorSisyphusAgent = createOrchestratorSisyphusAgent();
|
|
52215
52542
|
|
|
52216
52543
|
// src/agents/momus.ts
|
|
52217
|
-
var
|
|
52544
|
+
var DEFAULT_MODEL10 = "openai/gpt-5.2";
|
|
52218
52545
|
var MOMUS_SYSTEM_PROMPT = `You are a work plan review expert. You review the provided work plan (.sisyphus/plans/{name}.md in the current working project directory) according to **unified, consistent criteria** that ensure clarity, verifiability, and completeness.
|
|
52219
52546
|
|
|
52220
52547
|
**CRITICAL FIRST RULE**:
|
|
@@ -52544,7 +52871,7 @@ Use structured format, **in the same language as the work plan**.
|
|
|
52544
52871
|
|
|
52545
52872
|
**Strike the right balance**: Prevent critical failures while empowering developer autonomy.
|
|
52546
52873
|
`;
|
|
52547
|
-
function createMomusAgent(model =
|
|
52874
|
+
function createMomusAgent(model = DEFAULT_MODEL10) {
|
|
52548
52875
|
const restrictions = createAgentToolRestrictions([
|
|
52549
52876
|
"write",
|
|
52550
52877
|
"edit",
|
|
@@ -52575,8 +52902,8 @@ var agentSources = {
|
|
|
52575
52902
|
"frontend-ui-ux-engineer": createFrontendUiUxEngineerAgent,
|
|
52576
52903
|
"document-writer": createDocumentWriterAgent,
|
|
52577
52904
|
"multimodal-looker": createMultimodalLookerAgent,
|
|
52578
|
-
"Metis (Plan Consultant)":
|
|
52579
|
-
"Momus (Plan Reviewer)":
|
|
52905
|
+
"Metis (Plan Consultant)": createMetisAgent,
|
|
52906
|
+
"Momus (Plan Reviewer)": createMomusAgent,
|
|
52580
52907
|
"orchestrator-sisyphus": orchestratorSisyphusAgent
|
|
52581
52908
|
};
|
|
52582
52909
|
var agentMetadata = {
|
|
@@ -52689,7 +53016,11 @@ function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory
|
|
|
52689
53016
|
}
|
|
52690
53017
|
if (!disabledAgents.includes("orchestrator-sisyphus")) {
|
|
52691
53018
|
const orchestratorOverride = agentOverrides["orchestrator-sisyphus"];
|
|
52692
|
-
|
|
53019
|
+
const orchestratorModel = orchestratorOverride?.model;
|
|
53020
|
+
let orchestratorConfig = createOrchestratorSisyphusAgent({
|
|
53021
|
+
model: orchestratorModel,
|
|
53022
|
+
availableAgents
|
|
53023
|
+
});
|
|
52693
53024
|
if (orchestratorOverride) {
|
|
52694
53025
|
orchestratorConfig = mergeAgentConfig(orchestratorConfig, orchestratorOverride);
|
|
52695
53026
|
}
|