oh-my-opencode 4.1.0 → 4.1.2
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 +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.zh-cn.md +1 -1
- package/dist/cli/index.js +2261 -867
- package/dist/features/background-agent/manager.d.ts +7 -0
- package/dist/hooks/atlas/boulder-continuation-injector.d.ts +1 -1
- package/dist/hooks/ralph-loop/iteration-continuation.d.ts +1 -0
- package/dist/hooks/ralph-loop/loop-state-controller.d.ts +3 -3
- package/dist/hooks/ralph-loop/pending-verification-handler.d.ts +2 -1
- package/dist/hooks/ralph-loop/ralph-loop-event-handler.d.ts +2 -2
- package/dist/hooks/ralph-loop/storage.d.ts +2 -2
- package/dist/hooks/ralph-loop/types.d.ts +4 -0
- package/dist/hooks/ralph-loop/verification-failure-handler.d.ts +2 -2
- package/dist/hooks/shared/session-idle-settle.d.ts +9 -0
- package/dist/hooks/team-session-events/team-idle-wake-hint.d.ts +1 -0
- package/dist/hooks/unstable-agent-babysitter/unstable-agent-babysitter-hook.d.ts +1 -0
- package/dist/index.js +479 -149
- package/dist/shared/internal-initiator-marker.d.ts +8 -0
- package/dist/tools/delegate-task/subagent-discovery.d.ts +1 -0
- package/dist/tools/interactive-bash/constants.d.ts +1 -0
- package/package.json +23 -21
package/dist/index.js
CHANGED
|
@@ -54573,6 +54573,13 @@ function createInternalAgentTextPart(text) {
|
|
|
54573
54573
|
${OMO_INTERNAL_INITIATOR_MARKER}`
|
|
54574
54574
|
};
|
|
54575
54575
|
}
|
|
54576
|
+
function createInternalAgentContinuationTextPart(text) {
|
|
54577
|
+
return {
|
|
54578
|
+
...createInternalAgentTextPart(text),
|
|
54579
|
+
synthetic: true,
|
|
54580
|
+
metadata: { compaction_continue: true }
|
|
54581
|
+
};
|
|
54582
|
+
}
|
|
54576
54583
|
var OMO_INTERNAL_INITIATOR_MARKER = "<!-- OMO_INTERNAL_INITIATOR -->", INTERNAL_INITIATOR_MARKER_PATTERN;
|
|
54577
54584
|
var init_internal_initiator_marker = __esm(() => {
|
|
54578
54585
|
INTERNAL_INITIATOR_MARKER_PATTERN = /\n*<!--\s*OMO_INTERNAL_INITIATOR\s*-->\s*/g;
|
|
@@ -55991,6 +55998,7 @@ __export(exports_shared, {
|
|
|
55991
55998
|
createSystemDirective: () => createSystemDirective,
|
|
55992
55999
|
createModelCapabilitiesCacheStore: () => createModelCapabilitiesCacheStore,
|
|
55993
56000
|
createInternalAgentTextPart: () => createInternalAgentTextPart,
|
|
56001
|
+
createInternalAgentContinuationTextPart: () => createInternalAgentContinuationTextPart,
|
|
55994
56002
|
createDynamicTruncator: () => createDynamicTruncator,
|
|
55995
56003
|
createConnectedProvidersCacheStore: () => createConnectedProvidersCacheStore,
|
|
55996
56004
|
createAgentToolRestrictions: () => createAgentToolRestrictions,
|
|
@@ -58319,18 +58327,18 @@ function serializeRuntimeState(runtimeState) {
|
|
|
58319
58327
|
return `${JSON.stringify(parsedRuntimeState, null, 2)}
|
|
58320
58328
|
`;
|
|
58321
58329
|
}
|
|
58322
|
-
function
|
|
58330
|
+
function isRecord12(value) {
|
|
58323
58331
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
58324
58332
|
}
|
|
58325
58333
|
function stripLegacyRuntimeStateMemberFields(member) {
|
|
58326
|
-
if (!
|
|
58334
|
+
if (!isRecord12(member)) {
|
|
58327
58335
|
return member;
|
|
58328
58336
|
}
|
|
58329
58337
|
const { delegateTaskCallsUsed: _delegateTaskCallsUsed, ...memberWithoutLegacyFields } = member;
|
|
58330
58338
|
return memberWithoutLegacyFields;
|
|
58331
58339
|
}
|
|
58332
58340
|
function stripLegacyRuntimeStateFields(rawState) {
|
|
58333
|
-
if (!
|
|
58341
|
+
if (!isRecord12(rawState)) {
|
|
58334
58342
|
return rawState;
|
|
58335
58343
|
}
|
|
58336
58344
|
const members = rawState["members"];
|
|
@@ -58604,10 +58612,13 @@ function clearState(directory, customPath) {
|
|
|
58604
58612
|
return false;
|
|
58605
58613
|
}
|
|
58606
58614
|
}
|
|
58607
|
-
function incrementIteration(directory, customPath) {
|
|
58615
|
+
function incrementIteration(directory, customPath, expected) {
|
|
58608
58616
|
const state3 = readState(directory, customPath);
|
|
58609
58617
|
if (!state3)
|
|
58610
58618
|
return null;
|
|
58619
|
+
if (expected && (state3.iteration !== expected.iteration || state3.session_id !== expected.sessionID)) {
|
|
58620
|
+
return null;
|
|
58621
|
+
}
|
|
58611
58622
|
state3.iteration += 1;
|
|
58612
58623
|
if (writeState(directory, state3, customPath)) {
|
|
58613
58624
|
return state3;
|
|
@@ -69633,6 +69644,48 @@ init_logger();
|
|
|
69633
69644
|
init_opencode_storage_detection();
|
|
69634
69645
|
init_agent_display_names();
|
|
69635
69646
|
|
|
69647
|
+
// src/hooks/shared/session-idle-settle.ts
|
|
69648
|
+
var DEFAULT_SESSION_IDLE_SETTLE_MS = 150;
|
|
69649
|
+
function settleAfterSessionIdle(ms = DEFAULT_SESSION_IDLE_SETTLE_MS) {
|
|
69650
|
+
return ms > 0 ? new Promise((resolve8) => setTimeout(resolve8, ms)) : Promise.resolve();
|
|
69651
|
+
}
|
|
69652
|
+
var ACTIVE_SESSION_STATUSES = new Set(["busy", "retry", "running"]);
|
|
69653
|
+
function isRecord8(value) {
|
|
69654
|
+
return typeof value === "object" && value !== null;
|
|
69655
|
+
}
|
|
69656
|
+
function getSessionStatusPayload(response) {
|
|
69657
|
+
if (isRecord8(response) && isRecord8(response.data)) {
|
|
69658
|
+
return response.data;
|
|
69659
|
+
}
|
|
69660
|
+
if (isRecord8(response)) {
|
|
69661
|
+
return response;
|
|
69662
|
+
}
|
|
69663
|
+
return {};
|
|
69664
|
+
}
|
|
69665
|
+
function isActiveSessionStatusType(statusType) {
|
|
69666
|
+
return ACTIVE_SESSION_STATUSES.has(statusType);
|
|
69667
|
+
}
|
|
69668
|
+
async function isSessionActive(client, sessionID) {
|
|
69669
|
+
if (typeof client.session?.status !== "function") {
|
|
69670
|
+
return false;
|
|
69671
|
+
}
|
|
69672
|
+
try {
|
|
69673
|
+
const statusResult = await client.session.status();
|
|
69674
|
+
const status = getSessionStatusPayload(statusResult)[sessionID];
|
|
69675
|
+
if (!isRecord8(status)) {
|
|
69676
|
+
return false;
|
|
69677
|
+
}
|
|
69678
|
+
const statusType = status.type;
|
|
69679
|
+
return typeof statusType === "string" && isActiveSessionStatusType(statusType);
|
|
69680
|
+
} catch {
|
|
69681
|
+
return false;
|
|
69682
|
+
}
|
|
69683
|
+
}
|
|
69684
|
+
async function shouldPromptAfterSessionIdle(client, sessionID, settleMs = DEFAULT_SESSION_IDLE_SETTLE_MS) {
|
|
69685
|
+
await settleAfterSessionIdle(settleMs);
|
|
69686
|
+
return !await isSessionActive(client, sessionID);
|
|
69687
|
+
}
|
|
69688
|
+
|
|
69636
69689
|
// src/hooks/todo-continuation-enforcer/message-directory.ts
|
|
69637
69690
|
init_opencode_message_dir();
|
|
69638
69691
|
|
|
@@ -69906,6 +69959,10 @@ ${todoList}`;
|
|
|
69906
69959
|
log(`[${HOOK_NAME}] Skipped injection: session was cancelled before prompt`, { sessionID });
|
|
69907
69960
|
return;
|
|
69908
69961
|
}
|
|
69962
|
+
if (await isSessionActive(ctx.client, sessionID)) {
|
|
69963
|
+
log(`[${HOOK_NAME}] Skipped injection: session is active before prompt`, { sessionID });
|
|
69964
|
+
return;
|
|
69965
|
+
}
|
|
69909
69966
|
if (injectionState) {
|
|
69910
69967
|
injectionState.inFlight = true;
|
|
69911
69968
|
}
|
|
@@ -69926,7 +69983,7 @@ ${todoList}`;
|
|
|
69926
69983
|
...launchModel ? { model: launchModel } : {},
|
|
69927
69984
|
...launchVariant ? { variant: launchVariant } : {},
|
|
69928
69985
|
...inheritedTools ? { tools: inheritedTools } : {},
|
|
69929
|
-
parts: [
|
|
69986
|
+
parts: [createInternalAgentContinuationTextPart(prompt)]
|
|
69930
69987
|
},
|
|
69931
69988
|
query: { directory: ctx.directory }
|
|
69932
69989
|
});
|
|
@@ -71025,12 +71082,12 @@ async function playSessionNotificationSound(ctx, platform2, soundPath) {
|
|
|
71025
71082
|
}
|
|
71026
71083
|
|
|
71027
71084
|
// src/hooks/session-notification-event-properties.ts
|
|
71028
|
-
function
|
|
71085
|
+
function isRecord9(value) {
|
|
71029
71086
|
return typeof value === "object" && value !== null;
|
|
71030
71087
|
}
|
|
71031
71088
|
function getEventInfo(properties) {
|
|
71032
71089
|
const info = properties?.info;
|
|
71033
|
-
return
|
|
71090
|
+
return isRecord9(info) ? info : undefined;
|
|
71034
71091
|
}
|
|
71035
71092
|
function getSessionID(properties) {
|
|
71036
71093
|
const sessionID = properties?.sessionID;
|
|
@@ -71047,7 +71104,7 @@ function getSessionID(properties) {
|
|
|
71047
71104
|
if (typeof infoSessionId === "string" && infoSessionId.length > 0)
|
|
71048
71105
|
return infoSessionId;
|
|
71049
71106
|
const part = properties?.part;
|
|
71050
|
-
if (
|
|
71107
|
+
if (isRecord9(part)) {
|
|
71051
71108
|
const partSessionID = part.sessionID;
|
|
71052
71109
|
if (typeof partSessionID === "string" && partSessionID.length > 0)
|
|
71053
71110
|
return partSessionID;
|
|
@@ -71068,13 +71125,13 @@ function getEventToolName(properties) {
|
|
|
71068
71125
|
}
|
|
71069
71126
|
function getQuestionText(properties) {
|
|
71070
71127
|
const args = properties?.args;
|
|
71071
|
-
if (!
|
|
71128
|
+
if (!isRecord9(args))
|
|
71072
71129
|
return "";
|
|
71073
71130
|
const questions = args.questions;
|
|
71074
71131
|
if (!Array.isArray(questions) || questions.length === 0)
|
|
71075
71132
|
return "";
|
|
71076
71133
|
const firstQuestion = questions[0];
|
|
71077
|
-
if (!
|
|
71134
|
+
if (!isRecord9(firstQuestion))
|
|
71078
71135
|
return "";
|
|
71079
71136
|
const questionText = firstQuestion.question;
|
|
71080
71137
|
return typeof questionText === "string" ? questionText : "";
|
|
@@ -72304,7 +72361,7 @@ async function resumeSession(client, config) {
|
|
|
72304
72361
|
await client.session.promptAsync({
|
|
72305
72362
|
path: { id: config.sessionID },
|
|
72306
72363
|
body: {
|
|
72307
|
-
parts: [
|
|
72364
|
+
parts: [createInternalAgentContinuationTextPart(RECOVERY_RESUME_TEXT)],
|
|
72308
72365
|
agent: config.agent,
|
|
72309
72366
|
...launchModel ? { model: launchModel } : {},
|
|
72310
72367
|
...launchVariant ? { variant: launchVariant } : {},
|
|
@@ -74039,6 +74096,12 @@ async function runAggressiveTruncationStrategy(params) {
|
|
|
74039
74096
|
clearSessionState(params.autoCompactState, params.sessionID);
|
|
74040
74097
|
setTimeout(async () => {
|
|
74041
74098
|
try {
|
|
74099
|
+
if (await isSessionActive(params.client, params.sessionID)) {
|
|
74100
|
+
log("[auto-compact] skipped delayed auto prompt because session became active", {
|
|
74101
|
+
sessionID: params.sessionID
|
|
74102
|
+
});
|
|
74103
|
+
return;
|
|
74104
|
+
}
|
|
74042
74105
|
const sdkMessage = await findNearestMessageWithFieldsFromSDK(params.client, params.sessionID);
|
|
74043
74106
|
const previousMessage = sdkMessage ?? (() => {
|
|
74044
74107
|
const messageDir = getMessageDir(params.sessionID);
|
|
@@ -74060,7 +74123,12 @@ async function runAggressiveTruncationStrategy(params) {
|
|
|
74060
74123
|
},
|
|
74061
74124
|
query: { directory: params.directory }
|
|
74062
74125
|
});
|
|
74063
|
-
} catch {
|
|
74126
|
+
} catch (error) {
|
|
74127
|
+
log("[auto-compact] delayed auto prompt failed", {
|
|
74128
|
+
sessionID: params.sessionID,
|
|
74129
|
+
error: String(error)
|
|
74130
|
+
});
|
|
74131
|
+
}
|
|
74064
74132
|
}, 500);
|
|
74065
74133
|
return { handled: true, nextTruncateAttempt };
|
|
74066
74134
|
}
|
|
@@ -75408,6 +75476,12 @@ function getNextReachableFallback(sessionID, state3) {
|
|
|
75408
75476
|
}
|
|
75409
75477
|
|
|
75410
75478
|
// src/hooks/model-fallback/fallback-state-controller.ts
|
|
75479
|
+
function canonicalizeModelIDForDuplicateCheck(modelID) {
|
|
75480
|
+
return modelID.toLowerCase().replace(/\./g, "-");
|
|
75481
|
+
}
|
|
75482
|
+
function isSameFailedModel(state3, providerID, modelID) {
|
|
75483
|
+
return state3.providerID.toLowerCase() === providerID.toLowerCase() && canonicalizeModelIDForDuplicateCheck(state3.modelID) === canonicalizeModelIDForDuplicateCheck(modelID);
|
|
75484
|
+
}
|
|
75411
75485
|
function createModelFallbackStateController(input) {
|
|
75412
75486
|
const { pendingModelFallbacks, lastToastKey, sessionFallbackChains } = input;
|
|
75413
75487
|
function setSessionFallbackChain(sessionID, fallbackChain) {
|
|
@@ -75446,6 +75520,10 @@ function createModelFallbackStateController(input) {
|
|
|
75446
75520
|
log(`[model-fallback] Pending fallback already armed for session: ${sessionID}`);
|
|
75447
75521
|
return false;
|
|
75448
75522
|
}
|
|
75523
|
+
if (existing.attemptCount > 0 && isSameFailedModel(existing, currentProviderID, currentModelID)) {
|
|
75524
|
+
log(`[model-fallback] Ignoring duplicate fallback arm for already handled model in session: ${sessionID}`);
|
|
75525
|
+
return false;
|
|
75526
|
+
}
|
|
75449
75527
|
existing.providerID = currentProviderID;
|
|
75450
75528
|
existing.modelID = currentModelID;
|
|
75451
75529
|
existing.pending = true;
|
|
@@ -76690,7 +76768,7 @@ ${result.stderr.trim()}`);
|
|
|
76690
76768
|
|
|
76691
76769
|
// src/hooks/claude-code-hooks/handlers/tool-execute-after-handler.ts
|
|
76692
76770
|
init_shared();
|
|
76693
|
-
function
|
|
76771
|
+
function isRecord10(value) {
|
|
76694
76772
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
76695
76773
|
}
|
|
76696
76774
|
function getStringValue(record, key) {
|
|
@@ -76703,7 +76781,7 @@ function getNumberValue(record, key) {
|
|
|
76703
76781
|
}
|
|
76704
76782
|
function buildTranscriptToolOutput(outputText, metadata) {
|
|
76705
76783
|
const compactOutput = { output: outputText };
|
|
76706
|
-
if (!
|
|
76784
|
+
if (!isRecord10(metadata)) {
|
|
76707
76785
|
return compactOutput;
|
|
76708
76786
|
}
|
|
76709
76787
|
const filePath = getStringValue(metadata, "filePath") ?? getStringValue(metadata, "path") ?? getStringValue(metadata, "file");
|
|
@@ -76725,7 +76803,7 @@ function buildTranscriptToolOutput(outputText, metadata) {
|
|
|
76725
76803
|
}
|
|
76726
76804
|
}
|
|
76727
76805
|
const filediff = metadata.filediff;
|
|
76728
|
-
if (
|
|
76806
|
+
if (isRecord10(filediff)) {
|
|
76729
76807
|
const additions = getNumberValue(filediff, "additions");
|
|
76730
76808
|
const deletions = getNumberValue(filediff, "deletions");
|
|
76731
76809
|
if (additions !== undefined || deletions !== undefined) {
|
|
@@ -78695,14 +78773,14 @@ var defaultDeps3 = {
|
|
|
78695
78773
|
runBackgroundUpdateCheck,
|
|
78696
78774
|
log
|
|
78697
78775
|
};
|
|
78698
|
-
var
|
|
78776
|
+
var isRecord11 = (value) => {
|
|
78699
78777
|
return typeof value === "object" && value !== null;
|
|
78700
78778
|
};
|
|
78701
78779
|
var getParentID = (properties) => {
|
|
78702
|
-
if (!
|
|
78780
|
+
if (!isRecord11(properties))
|
|
78703
78781
|
return;
|
|
78704
78782
|
const { info } = properties;
|
|
78705
|
-
if (!
|
|
78783
|
+
if (!isRecord11(info))
|
|
78706
78784
|
return;
|
|
78707
78785
|
const { parentID } = info;
|
|
78708
78786
|
return typeof parentID === "string" && parentID.length > 0 ? parentID : undefined;
|
|
@@ -80171,6 +80249,31 @@ function detectBannedCommand(command) {
|
|
|
80171
80249
|
}
|
|
80172
80250
|
return;
|
|
80173
80251
|
}
|
|
80252
|
+
function detectWindowsShellType(shellPath) {
|
|
80253
|
+
if (!shellPath) {
|
|
80254
|
+
return;
|
|
80255
|
+
}
|
|
80256
|
+
const shellName = shellPath.replace(/\\/g, "/").split("/").pop()?.toLowerCase();
|
|
80257
|
+
if (shellName === "cmd" || shellName === "cmd.exe") {
|
|
80258
|
+
return "cmd";
|
|
80259
|
+
}
|
|
80260
|
+
if (shellName === "powershell" || shellName === "powershell.exe" || shellName === "pwsh" || shellName === "pwsh.exe") {
|
|
80261
|
+
return "powershell";
|
|
80262
|
+
}
|
|
80263
|
+
return;
|
|
80264
|
+
}
|
|
80265
|
+
function detectCommandShellType() {
|
|
80266
|
+
if (process.platform === "win32" && process.env.SHELL) {
|
|
80267
|
+
const shellType = detectWindowsShellType(process.env.SHELL);
|
|
80268
|
+
if (shellType) {
|
|
80269
|
+
return shellType;
|
|
80270
|
+
}
|
|
80271
|
+
}
|
|
80272
|
+
if (process.platform === "win32" && !process.env.SHELL && !process.env.MSYSTEM) {
|
|
80273
|
+
return detectWindowsShellType(process.env.ComSpec) ?? "cmd";
|
|
80274
|
+
}
|
|
80275
|
+
return detectShellType();
|
|
80276
|
+
}
|
|
80174
80277
|
function createNonInteractiveEnvHook(_ctx) {
|
|
80175
80278
|
return {
|
|
80176
80279
|
"tool.execute.before": async (input, output) => {
|
|
@@ -80189,7 +80292,7 @@ function createNonInteractiveEnvHook(_ctx) {
|
|
|
80189
80292
|
if (!isGitCommand) {
|
|
80190
80293
|
return;
|
|
80191
80294
|
}
|
|
80192
|
-
const shellType =
|
|
80295
|
+
const shellType = detectCommandShellType();
|
|
80193
80296
|
const envPrefix = buildEnvPrefix(NON_INTERACTIVE_ENV, shellType);
|
|
80194
80297
|
if (command.trim().startsWith(envPrefix.trim())) {
|
|
80195
80298
|
return;
|
|
@@ -81111,8 +81214,8 @@ function createLoopStateController(options) {
|
|
|
81111
81214
|
clear() {
|
|
81112
81215
|
return clearState(directory, stateDir);
|
|
81113
81216
|
},
|
|
81114
|
-
incrementIteration() {
|
|
81115
|
-
return incrementIteration(directory, stateDir);
|
|
81217
|
+
incrementIteration(expected) {
|
|
81218
|
+
return incrementIteration(directory, stateDir, expected);
|
|
81116
81219
|
},
|
|
81117
81220
|
setSessionID(sessionID) {
|
|
81118
81221
|
const state3 = readState(directory, stateDir);
|
|
@@ -81125,11 +81228,14 @@ function createLoopStateController(options) {
|
|
|
81125
81228
|
}
|
|
81126
81229
|
return state3;
|
|
81127
81230
|
},
|
|
81128
|
-
setMessageCountAtStart(sessionID, messageCountAtStart) {
|
|
81231
|
+
setMessageCountAtStart(sessionID, messageCountAtStart, expectedStartedAt) {
|
|
81129
81232
|
const state3 = readState(directory, stateDir);
|
|
81130
81233
|
if (!state3 || state3.session_id !== sessionID) {
|
|
81131
81234
|
return null;
|
|
81132
81235
|
}
|
|
81236
|
+
if (state3.iteration !== 1 || state3.verification_pending || state3.message_count_at_start !== undefined || expectedStartedAt !== undefined && state3.started_at !== expectedStartedAt) {
|
|
81237
|
+
return null;
|
|
81238
|
+
}
|
|
81133
81239
|
state3.message_count_at_start = messageCountAtStart;
|
|
81134
81240
|
if (!writeState(directory, state3, stateDir)) {
|
|
81135
81241
|
return null;
|
|
@@ -81366,7 +81472,7 @@ async function injectContinuationPrompt(ctx, options) {
|
|
|
81366
81472
|
...launchModel ? { model: launchModel } : {},
|
|
81367
81473
|
...launchVariant ? { variant: launchVariant } : {},
|
|
81368
81474
|
...inheritedTools ? { tools: inheritedTools } : {},
|
|
81369
|
-
parts: [
|
|
81475
|
+
parts: [createInternalAgentContinuationTextPart(options.prompt)]
|
|
81370
81476
|
},
|
|
81371
81477
|
query: { directory: options.directory }
|
|
81372
81478
|
});
|
|
@@ -81496,7 +81602,7 @@ function resolveToolCallID(ctx) {
|
|
|
81496
81602
|
}
|
|
81497
81603
|
// src/features/tool-metadata-store/task-metadata-contract.ts
|
|
81498
81604
|
init_logger();
|
|
81499
|
-
function
|
|
81605
|
+
function isRecord13(value) {
|
|
81500
81606
|
return typeof value === "object" && value !== null;
|
|
81501
81607
|
}
|
|
81502
81608
|
function readString2(value) {
|
|
@@ -81581,7 +81687,7 @@ function parseTaskMetadataBlock(text) {
|
|
|
81581
81687
|
return parsed;
|
|
81582
81688
|
}
|
|
81583
81689
|
function extractTaskLink(metadata, outputText) {
|
|
81584
|
-
if (
|
|
81690
|
+
if (isRecord13(metadata)) {
|
|
81585
81691
|
const metadataLink = {
|
|
81586
81692
|
sessionId: readSessionIdFromMetadata(metadata),
|
|
81587
81693
|
taskId: readTaskIdFromMetadata(metadata),
|
|
@@ -81879,9 +81985,9 @@ async function continueIteration(ctx, state3, options) {
|
|
|
81879
81985
|
previousSessionID: options.previousSessionID,
|
|
81880
81986
|
newSessionID
|
|
81881
81987
|
});
|
|
81882
|
-
return { status: "
|
|
81988
|
+
return { status: "dispatch_rejected", error: "state commit failed after reset dispatch" };
|
|
81883
81989
|
}
|
|
81884
|
-
return { status: "dispatched" };
|
|
81990
|
+
return { status: "dispatched", sessionID: newSessionID };
|
|
81885
81991
|
}
|
|
81886
81992
|
try {
|
|
81887
81993
|
const promptResult = await injectContinuationPrompt(ctx, {
|
|
@@ -81896,7 +82002,7 @@ async function continueIteration(ctx, state3, options) {
|
|
|
81896
82002
|
} catch (error) {
|
|
81897
82003
|
return { status: "dispatch_rejected", error };
|
|
81898
82004
|
}
|
|
81899
|
-
return { status: "dispatched" };
|
|
82005
|
+
return { status: "dispatched", sessionID: options.previousSessionID };
|
|
81900
82006
|
}
|
|
81901
82007
|
|
|
81902
82008
|
// src/hooks/ralph-loop/pending-verification-handler.ts
|
|
@@ -82352,6 +82458,10 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
82352
82458
|
});
|
|
82353
82459
|
return;
|
|
82354
82460
|
}
|
|
82461
|
+
if (await isSessionActive(ctx.client, sessionID)) {
|
|
82462
|
+
log(`[${HOOK_NAME3}] Skipped: session became active during settle window`, { sessionID });
|
|
82463
|
+
return;
|
|
82464
|
+
}
|
|
82355
82465
|
if (stateAfterSettle.verification_pending) {
|
|
82356
82466
|
log(`[${HOOK_NAME3}] Skipped: state entered verification_pending during settle window`, { sessionID });
|
|
82357
82467
|
return;
|
|
@@ -82390,11 +82500,21 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
82390
82500
|
})) {
|
|
82391
82501
|
return;
|
|
82392
82502
|
}
|
|
82393
|
-
const committed = options.loopState.incrementIteration(
|
|
82503
|
+
const committed = options.loopState.incrementIteration({
|
|
82504
|
+
iteration: stateBeforeCommit.iteration,
|
|
82505
|
+
sessionID: result.sessionID
|
|
82506
|
+
});
|
|
82394
82507
|
if (committed) {
|
|
82395
82508
|
showIterationToast(ctx, committed);
|
|
82396
82509
|
} else {
|
|
82397
82510
|
log(`[${HOOK_NAME3}] Dispatch succeeded but iteration commit failed`, { sessionID });
|
|
82511
|
+
options.loopState.clear();
|
|
82512
|
+
showToastBestEffort3(ctx, {
|
|
82513
|
+
title: "Ralph Loop Failed",
|
|
82514
|
+
message: "Dispatch succeeded but iteration commit failed",
|
|
82515
|
+
variant: "warning",
|
|
82516
|
+
duration: 5000
|
|
82517
|
+
});
|
|
82398
82518
|
}
|
|
82399
82519
|
return;
|
|
82400
82520
|
}
|
|
@@ -82485,6 +82605,10 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
82485
82605
|
});
|
|
82486
82606
|
return;
|
|
82487
82607
|
}
|
|
82608
|
+
if (await isSessionActive(ctx.client, sessionID)) {
|
|
82609
|
+
log(`[${HOOK_NAME3}] Skipped: session became active during settle window`, { sessionID });
|
|
82610
|
+
return;
|
|
82611
|
+
}
|
|
82488
82612
|
if (stateAfterSettle.verification_pending) {
|
|
82489
82613
|
log(`[${HOOK_NAME3}] Skipped: state entered verification_pending during settle window`, { sessionID });
|
|
82490
82614
|
return;
|
|
@@ -82518,12 +82642,22 @@ function createRalphLoopEventHandler(ctx, options) {
|
|
|
82518
82642
|
})) {
|
|
82519
82643
|
return;
|
|
82520
82644
|
}
|
|
82521
|
-
const committed = options.loopState.incrementIteration(
|
|
82645
|
+
const committed = options.loopState.incrementIteration({
|
|
82646
|
+
iteration: stateBeforeCommit.iteration,
|
|
82647
|
+
sessionID: result.sessionID
|
|
82648
|
+
});
|
|
82522
82649
|
if (committed) {
|
|
82523
82650
|
showIterationToast(ctx, committed);
|
|
82524
82651
|
runtimeErrorRetriedSessions.set(sessionID, committed.iteration);
|
|
82525
82652
|
} else {
|
|
82526
82653
|
log(`[${HOOK_NAME3}] Dispatch succeeded but iteration commit failed after runtime error`, { sessionID });
|
|
82654
|
+
options.loopState.clear();
|
|
82655
|
+
showToastBestEffort3(ctx, {
|
|
82656
|
+
title: "Ralph Loop Failed",
|
|
82657
|
+
message: "Dispatch succeeded but iteration commit failed",
|
|
82658
|
+
variant: "warning",
|
|
82659
|
+
duration: 5000
|
|
82660
|
+
});
|
|
82527
82661
|
}
|
|
82528
82662
|
return;
|
|
82529
82663
|
}
|
|
@@ -82584,12 +82718,14 @@ function createRalphLoopHook(ctx, options) {
|
|
|
82584
82718
|
if (!startSuccess || typeof loopOptions?.messageCountAtStart === "number") {
|
|
82585
82719
|
return startSuccess;
|
|
82586
82720
|
}
|
|
82721
|
+
const startedState = loopState.getState();
|
|
82722
|
+
const expectedStartedAt = startedState?.session_id === sessionID ? startedState.started_at : undefined;
|
|
82587
82723
|
ctx.client.session.messages({
|
|
82588
82724
|
path: { id: sessionID },
|
|
82589
82725
|
query: { directory: ctx.directory }
|
|
82590
82726
|
}).then((messagesResponse) => {
|
|
82591
82727
|
const messageCountAtStart = getMessageCountFromResponse2(messagesResponse);
|
|
82592
|
-
loopState.setMessageCountAtStart(sessionID, messageCountAtStart);
|
|
82728
|
+
loopState.setMessageCountAtStart(sessionID, messageCountAtStart, expectedStartedAt);
|
|
82593
82729
|
}).catch(() => {});
|
|
82594
82730
|
return startSuccess;
|
|
82595
82731
|
},
|
|
@@ -89383,7 +89519,7 @@ function createProcessedCommandStore() {
|
|
|
89383
89519
|
|
|
89384
89520
|
// src/hooks/auto-slash-command/hook.ts
|
|
89385
89521
|
var COMMAND_EXECUTE_FALLBACK_DEDUP_TTL_MS = 100;
|
|
89386
|
-
function
|
|
89522
|
+
function isRecord14(value) {
|
|
89387
89523
|
return typeof value === "object" && value !== null;
|
|
89388
89524
|
}
|
|
89389
89525
|
function getDeletedSessionID(properties) {
|
|
@@ -89401,7 +89537,7 @@ function getCommandExecutionEventID(input) {
|
|
|
89401
89537
|
"commandId"
|
|
89402
89538
|
];
|
|
89403
89539
|
const recordInput = input;
|
|
89404
|
-
if (!
|
|
89540
|
+
if (!isRecord14(recordInput)) {
|
|
89405
89541
|
return null;
|
|
89406
89542
|
}
|
|
89407
89543
|
for (const key of candidateKeys) {
|
|
@@ -91211,12 +91347,6 @@ init_shared();
|
|
|
91211
91347
|
init_agent_display_names();
|
|
91212
91348
|
init_logger();
|
|
91213
91349
|
|
|
91214
|
-
// src/hooks/shared/session-idle-settle.ts
|
|
91215
|
-
var DEFAULT_SESSION_IDLE_SETTLE_MS = 150;
|
|
91216
|
-
function settleAfterSessionIdle(ms = DEFAULT_SESSION_IDLE_SETTLE_MS) {
|
|
91217
|
-
return ms > 0 ? new Promise((resolve14) => setTimeout(resolve14, ms)) : Promise.resolve();
|
|
91218
|
-
}
|
|
91219
|
-
|
|
91220
91350
|
// src/hooks/atlas/boulder-continuation-injector.ts
|
|
91221
91351
|
init_logger();
|
|
91222
91352
|
init_shared();
|
|
@@ -91500,6 +91630,10 @@ async function injectBoulderContinuation(input) {
|
|
|
91500
91630
|
return "skipped_agent_unavailable";
|
|
91501
91631
|
}
|
|
91502
91632
|
try {
|
|
91633
|
+
if (await isSessionActive(ctx.client, sessionID)) {
|
|
91634
|
+
log(`[${HOOK_NAME7}] Skipped injection: session is active`, { sessionID });
|
|
91635
|
+
return "skipped_active_session";
|
|
91636
|
+
}
|
|
91503
91637
|
log(`[${HOOK_NAME7}] Injecting boulder continuation`, { sessionID, planName, remaining });
|
|
91504
91638
|
const promptContext = await resolveRecentPromptContextForSession(ctx, sessionID);
|
|
91505
91639
|
const inheritedTools = resolveInheritedPromptTools(sessionID, promptContext.tools);
|
|
@@ -91512,7 +91646,7 @@ async function injectBoulderContinuation(input) {
|
|
|
91512
91646
|
...launchModel ? { model: launchModel } : {},
|
|
91513
91647
|
...launchVariant ? { variant: launchVariant } : {},
|
|
91514
91648
|
...inheritedTools ? { tools: inheritedTools } : {},
|
|
91515
|
-
parts: [
|
|
91649
|
+
parts: [createInternalAgentContinuationTextPart(prompt)]
|
|
91516
91650
|
},
|
|
91517
91651
|
query: { directory: ctx.directory }
|
|
91518
91652
|
});
|
|
@@ -91760,11 +91894,15 @@ async function handleAtlasSessionIdle(input) {
|
|
|
91760
91894
|
const prompt = BOULDER_COMPLETE_PROMPT.replace(/{PLAN_NAME}/g, work.plan_name).replace(/{ELAPSED_HUMAN}/g, elapsedHuman).replace(/{TASK_BREAKDOWN}/g, taskBreakdown.length > 0 ? taskBreakdown : "- (no task timings)");
|
|
91761
91895
|
const atlasAgent = resolveRegisteredAgentName(boulderState.agent ?? (isAgentRegistered("atlas") ? "atlas" : undefined));
|
|
91762
91896
|
if (atlasAgent && isAgentRegistered(atlasAgent)) {
|
|
91897
|
+
if (!await shouldPromptAfterSessionIdle(ctx.client, sessionID, options?.idleSettleMs)) {
|
|
91898
|
+
log(`[${HOOK_NAME7}] Boulder completion nudge skipped because session is active`, { sessionID });
|
|
91899
|
+
return;
|
|
91900
|
+
}
|
|
91763
91901
|
await ctx.client.session.promptAsync({
|
|
91764
91902
|
path: { id: sessionID },
|
|
91765
91903
|
body: {
|
|
91766
91904
|
agent: atlasAgent,
|
|
91767
|
-
parts: [
|
|
91905
|
+
parts: [createInternalAgentContinuationTextPart(prompt)]
|
|
91768
91906
|
},
|
|
91769
91907
|
query: { directory: ctx.directory }
|
|
91770
91908
|
});
|
|
@@ -91842,7 +91980,10 @@ async function handleAtlasSessionIdle(input) {
|
|
|
91842
91980
|
});
|
|
91843
91981
|
return;
|
|
91844
91982
|
}
|
|
91845
|
-
await
|
|
91983
|
+
if (!await shouldPromptAfterSessionIdle(ctx.client, sessionID, options?.idleSettleMs)) {
|
|
91984
|
+
log(`[${HOOK_NAME7}] Skipped: session became active during idle settle`, { sessionID });
|
|
91985
|
+
return;
|
|
91986
|
+
}
|
|
91846
91987
|
await injectContinuation2({
|
|
91847
91988
|
ctx,
|
|
91848
91989
|
sessionID,
|
|
@@ -93483,7 +93624,7 @@ function createRecoveryLogic(ctx, getTailState) {
|
|
|
93483
93624
|
agent: launchAgent ?? expectedPromptConfig.agent,
|
|
93484
93625
|
...model ? { model } : {},
|
|
93485
93626
|
...tools ? { tools } : {},
|
|
93486
|
-
parts: [
|
|
93627
|
+
parts: [createInternalAgentContinuationTextPart(AGENT_RECOVERY_PROMPT)]
|
|
93487
93628
|
},
|
|
93488
93629
|
query: { directory: ctx.directory }
|
|
93489
93630
|
});
|
|
@@ -93889,16 +94030,16 @@ var THINKING_SUMMARY_MAX_CHARS = 500;
|
|
|
93889
94030
|
function hasData(value) {
|
|
93890
94031
|
return typeof value === "object" && value !== null && "data" in value;
|
|
93891
94032
|
}
|
|
93892
|
-
function
|
|
94033
|
+
function isRecord15(value) {
|
|
93893
94034
|
return typeof value === "object" && value !== null;
|
|
93894
94035
|
}
|
|
93895
94036
|
function getMessageInfo(value) {
|
|
93896
|
-
if (!
|
|
94037
|
+
if (!isRecord15(value))
|
|
93897
94038
|
return;
|
|
93898
|
-
if (!
|
|
94039
|
+
if (!isRecord15(value.info))
|
|
93899
94040
|
return;
|
|
93900
94041
|
const info = value.info;
|
|
93901
|
-
const modelValue =
|
|
94042
|
+
const modelValue = isRecord15(info.model) ? info.model : undefined;
|
|
93902
94043
|
const model = modelValue && typeof modelValue.providerID === "string" && typeof modelValue.modelID === "string" ? {
|
|
93903
94044
|
providerID: modelValue.providerID,
|
|
93904
94045
|
modelID: modelValue.modelID,
|
|
@@ -93910,7 +94051,7 @@ function getMessageInfo(value) {
|
|
|
93910
94051
|
model,
|
|
93911
94052
|
providerID: typeof info.providerID === "string" ? info.providerID : undefined,
|
|
93912
94053
|
modelID: typeof info.modelID === "string" ? info.modelID : undefined,
|
|
93913
|
-
tools:
|
|
94054
|
+
tools: isRecord15(info.tools) ? Object.entries(info.tools).reduce((acc, [key, value2]) => {
|
|
93914
94055
|
if (value2 === true || value2 === false || value2 === "allow" || value2 === "deny" || value2 === "ask") {
|
|
93915
94056
|
acc[key] = value2;
|
|
93916
94057
|
}
|
|
@@ -93919,11 +94060,11 @@ function getMessageInfo(value) {
|
|
|
93919
94060
|
};
|
|
93920
94061
|
}
|
|
93921
94062
|
function getMessageParts(value) {
|
|
93922
|
-
if (!
|
|
94063
|
+
if (!isRecord15(value))
|
|
93923
94064
|
return [];
|
|
93924
94065
|
if (!Array.isArray(value.parts))
|
|
93925
94066
|
return [];
|
|
93926
|
-
return value.parts.filter(
|
|
94067
|
+
return value.parts.filter(isRecord15).map((part) => ({
|
|
93927
94068
|
type: typeof part.type === "string" ? part.type : undefined,
|
|
93928
94069
|
text: typeof part.text === "string" ? part.text : undefined,
|
|
93929
94070
|
thinking: typeof part.thinking === "string" ? part.thinking : undefined
|
|
@@ -94108,7 +94249,10 @@ function createUnstableAgentBabysitterHook(ctx, options) {
|
|
|
94108
94249
|
try {
|
|
94109
94250
|
const launchModel = model ? { providerID: model.providerID, modelID: model.modelID } : undefined;
|
|
94110
94251
|
const launchVariant = model?.variant;
|
|
94111
|
-
await
|
|
94252
|
+
if (!await shouldPromptAfterSessionIdle(ctx.client, mainSessionID, options.idleSettleMs)) {
|
|
94253
|
+
log(`[${HOOK_NAME10}] Reminder skipped because main session is active`, { taskId: task.id, sessionID: mainSessionID });
|
|
94254
|
+
continue;
|
|
94255
|
+
}
|
|
94112
94256
|
await ctx.client.session.promptAsync({
|
|
94113
94257
|
path: { id: mainSessionID },
|
|
94114
94258
|
body: {
|
|
@@ -94736,11 +94880,11 @@ function buildRetryModelPayload(model, agentSettings) {
|
|
|
94736
94880
|
}
|
|
94737
94881
|
|
|
94738
94882
|
// src/hooks/runtime-fallback/session-messages.ts
|
|
94739
|
-
function
|
|
94883
|
+
function isRecord16(value) {
|
|
94740
94884
|
return typeof value === "object" && value !== null;
|
|
94741
94885
|
}
|
|
94742
94886
|
function isSessionMessage(value) {
|
|
94743
|
-
return
|
|
94887
|
+
return isRecord16(value);
|
|
94744
94888
|
}
|
|
94745
94889
|
function isSessionMessageArray(value) {
|
|
94746
94890
|
return Array.isArray(value) && value.every(isSessionMessage);
|
|
@@ -94749,7 +94893,7 @@ function extractSessionMessages(messagesResponse) {
|
|
|
94749
94893
|
if (isSessionMessageArray(messagesResponse)) {
|
|
94750
94894
|
return messagesResponse;
|
|
94751
94895
|
}
|
|
94752
|
-
if (!
|
|
94896
|
+
if (!isRecord16(messagesResponse)) {
|
|
94753
94897
|
return;
|
|
94754
94898
|
}
|
|
94755
94899
|
const data = messagesResponse.data;
|
|
@@ -95301,6 +95445,18 @@ function createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys) {
|
|
|
95301
95445
|
|
|
95302
95446
|
// src/hooks/runtime-fallback/event-handler.ts
|
|
95303
95447
|
init_event_session_id();
|
|
95448
|
+
function resolveEventModel(props) {
|
|
95449
|
+
const model = props?.model;
|
|
95450
|
+
if (typeof model === "string") {
|
|
95451
|
+
return model;
|
|
95452
|
+
}
|
|
95453
|
+
const providerID = props?.providerID;
|
|
95454
|
+
const modelID = props?.modelID;
|
|
95455
|
+
if (typeof providerID === "string" && typeof modelID === "string") {
|
|
95456
|
+
return `${providerID}/${modelID}`;
|
|
95457
|
+
}
|
|
95458
|
+
return;
|
|
95459
|
+
}
|
|
95304
95460
|
function createEventHandler(deps, helpers) {
|
|
95305
95461
|
const { config, pluginConfig, sessionStates, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionFallbackTimeouts, sessionStatusRetryKeys } = deps;
|
|
95306
95462
|
const sessionStatusHandler = createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys);
|
|
@@ -95405,6 +95561,18 @@ function createEventHandler(deps, helpers) {
|
|
|
95405
95561
|
});
|
|
95406
95562
|
return;
|
|
95407
95563
|
}
|
|
95564
|
+
if (sessionAwaitingFallbackResult.has(sessionID)) {
|
|
95565
|
+
const pendingFallbackModel = sessionStates.get(sessionID)?.pendingFallbackModel;
|
|
95566
|
+
const eventModel = resolveEventModel(props);
|
|
95567
|
+
if (!pendingFallbackModel || eventModel !== pendingFallbackModel) {
|
|
95568
|
+
log(`[${HOOK_NAME11}] session.error skipped - awaiting fallback result`, {
|
|
95569
|
+
sessionID,
|
|
95570
|
+
pendingFallbackModel,
|
|
95571
|
+
eventModel
|
|
95572
|
+
});
|
|
95573
|
+
return;
|
|
95574
|
+
}
|
|
95575
|
+
}
|
|
95408
95576
|
sessionAwaitingFallbackResult.delete(sessionID);
|
|
95409
95577
|
helpers.clearSessionFallbackTimeout(sessionID);
|
|
95410
95578
|
log(`[${HOOK_NAME11}] session.error received`, {
|
|
@@ -101171,7 +101339,7 @@ function normalizeToolArgSchemas(toolDefinition) {
|
|
|
101171
101339
|
return toolDefinition;
|
|
101172
101340
|
}
|
|
101173
101341
|
var UNSUPPORTED_SCHEMA_KEYWORDS = new Set(["contentEncoding", "contentMediaType"]);
|
|
101174
|
-
function
|
|
101342
|
+
function isRecord17(value) {
|
|
101175
101343
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
101176
101344
|
}
|
|
101177
101345
|
function normalizeJsonSchemaRef(value) {
|
|
@@ -101184,7 +101352,7 @@ function sanitizeJsonSchema(value, depth = 0, isPropertyName = false) {
|
|
|
101184
101352
|
if (Array.isArray(value)) {
|
|
101185
101353
|
return value.map((item) => sanitizeJsonSchema(item, depth + 1, false));
|
|
101186
101354
|
}
|
|
101187
|
-
if (!
|
|
101355
|
+
if (!isRecord17(value)) {
|
|
101188
101356
|
return value;
|
|
101189
101357
|
}
|
|
101190
101358
|
const sanitized = {};
|
|
@@ -102344,6 +102512,9 @@ var BLOCKED_TMUX_SUBCOMMANDS = [
|
|
|
102344
102512
|
"pipe-pane",
|
|
102345
102513
|
"pipep"
|
|
102346
102514
|
];
|
|
102515
|
+
var PROHIBITED_TMUX_SUBCOMMANDS = [
|
|
102516
|
+
"kill-server"
|
|
102517
|
+
];
|
|
102347
102518
|
var INTERACTIVE_BASH_DESCRIPTION = `WARNING: This is TMUX ONLY. Pass tmux subcommands directly (without 'tmux' prefix).
|
|
102348
102519
|
|
|
102349
102520
|
Examples: new-session -d -s omo-dev, send-keys -t omo-dev "vim" Enter
|
|
@@ -102352,6 +102523,7 @@ For TUI apps needing ongoing interaction (vim, htop, pudb). One-shot commands \u
|
|
|
102352
102523
|
|
|
102353
102524
|
// src/tools/interactive-bash/tools.ts
|
|
102354
102525
|
init_tmux_path_resolver();
|
|
102526
|
+
var GLOBAL_TMUX_OPTIONS_WITH_ARGS = new Set(["-L", "-S", "-f", "-c", "-T"]);
|
|
102355
102527
|
function resolveTmuxExecutable2(tmuxPath2) {
|
|
102356
102528
|
if (!isCmuxCompatEnvironment()) {
|
|
102357
102529
|
return [tmuxPath2];
|
|
@@ -102396,6 +102568,71 @@ function tokenizeCommand2(cmd) {
|
|
|
102396
102568
|
tokens.push(current);
|
|
102397
102569
|
return tokens;
|
|
102398
102570
|
}
|
|
102571
|
+
function findSubcommandIndex(parts) {
|
|
102572
|
+
let index = 0;
|
|
102573
|
+
while (index < parts.length) {
|
|
102574
|
+
const part = parts[index] ?? "";
|
|
102575
|
+
if (part === "--") {
|
|
102576
|
+
return index + 1 < parts.length ? index + 1 : -1;
|
|
102577
|
+
}
|
|
102578
|
+
if (GLOBAL_TMUX_OPTIONS_WITH_ARGS.has(part)) {
|
|
102579
|
+
index += 2;
|
|
102580
|
+
continue;
|
|
102581
|
+
}
|
|
102582
|
+
if (part.startsWith("-")) {
|
|
102583
|
+
index++;
|
|
102584
|
+
continue;
|
|
102585
|
+
}
|
|
102586
|
+
return index;
|
|
102587
|
+
}
|
|
102588
|
+
return -1;
|
|
102589
|
+
}
|
|
102590
|
+
function getTargetSessionName(parts) {
|
|
102591
|
+
const sessionIdx = parts.findIndex((p) => p === "-t" || p.startsWith("-t"));
|
|
102592
|
+
if (sessionIdx === -1) {
|
|
102593
|
+
return "omo-session";
|
|
102594
|
+
}
|
|
102595
|
+
const sessionToken = parts[sessionIdx] ?? "";
|
|
102596
|
+
const nextToken = parts[sessionIdx + 1];
|
|
102597
|
+
if (sessionToken === "-t" && nextToken) {
|
|
102598
|
+
return nextToken;
|
|
102599
|
+
}
|
|
102600
|
+
if (sessionToken.startsWith("-t")) {
|
|
102601
|
+
return sessionToken.slice(2);
|
|
102602
|
+
}
|
|
102603
|
+
return "omo-session";
|
|
102604
|
+
}
|
|
102605
|
+
function buildBlockedTmuxCommandMessage(command, parts) {
|
|
102606
|
+
const sessionName = getTargetSessionName(parts);
|
|
102607
|
+
return `Error: '${command}' is blocked in interactive_bash.
|
|
102608
|
+
|
|
102609
|
+
**USE BASH TOOL INSTEAD:**
|
|
102610
|
+
|
|
102611
|
+
\`\`\`bash
|
|
102612
|
+
# Capture terminal output
|
|
102613
|
+
tmux capture-pane -p -t ${sessionName}
|
|
102614
|
+
|
|
102615
|
+
# Or capture with history (last 1000 lines)
|
|
102616
|
+
tmux capture-pane -p -t ${sessionName} -S -1000
|
|
102617
|
+
\`\`\`
|
|
102618
|
+
|
|
102619
|
+
The Bash tool can execute these commands directly. Do NOT retry with interactive_bash.`;
|
|
102620
|
+
}
|
|
102621
|
+
function buildProhibitedTmuxCommandMessage(command) {
|
|
102622
|
+
return `Error: '${command}' is prohibited in interactive_bash.
|
|
102623
|
+
|
|
102624
|
+
NEVER EVER run tmux kill-server from interactive_bash.
|
|
102625
|
+
|
|
102626
|
+
It terminates the entire tmux server, destroying every tmux session and pane that the user, Codex, or other agents may be using.
|
|
102627
|
+
|
|
102628
|
+
Use scoped cleanup only:
|
|
102629
|
+
|
|
102630
|
+
\`\`\`bash
|
|
102631
|
+
tmux kill-session -t <session-name>
|
|
102632
|
+
\`\`\`
|
|
102633
|
+
|
|
102634
|
+
If you created an omo-* session, kill only that exact session. Do not retry kill-server with Bash or any other tool.`;
|
|
102635
|
+
}
|
|
102399
102636
|
var interactive_bash = tool({
|
|
102400
102637
|
description: INTERACTIVE_BASH_DESCRIPTION,
|
|
102401
102638
|
args: {
|
|
@@ -102408,30 +102645,14 @@ var interactive_bash = tool({
|
|
|
102408
102645
|
if (parts.length === 0) {
|
|
102409
102646
|
return "Error: Empty tmux command";
|
|
102410
102647
|
}
|
|
102411
|
-
const
|
|
102648
|
+
const subcommandIndex = findSubcommandIndex(parts);
|
|
102649
|
+
const rawSubcommand = subcommandIndex === -1 ? "" : parts[subcommandIndex];
|
|
102650
|
+
const subcommand = rawSubcommand.toLowerCase();
|
|
102651
|
+
if (PROHIBITED_TMUX_SUBCOMMANDS.includes(subcommand)) {
|
|
102652
|
+
return buildProhibitedTmuxCommandMessage(rawSubcommand);
|
|
102653
|
+
}
|
|
102412
102654
|
if (BLOCKED_TMUX_SUBCOMMANDS.includes(subcommand)) {
|
|
102413
|
-
|
|
102414
|
-
let sessionName = "omo-session";
|
|
102415
|
-
if (sessionIdx !== -1) {
|
|
102416
|
-
if (parts[sessionIdx] === "-t" && parts[sessionIdx + 1]) {
|
|
102417
|
-
sessionName = parts[sessionIdx + 1];
|
|
102418
|
-
} else if (parts[sessionIdx].startsWith("-t")) {
|
|
102419
|
-
sessionName = parts[sessionIdx].slice(2);
|
|
102420
|
-
}
|
|
102421
|
-
}
|
|
102422
|
-
return `Error: '${parts[0]}' is blocked in interactive_bash.
|
|
102423
|
-
|
|
102424
|
-
**USE BASH TOOL INSTEAD:**
|
|
102425
|
-
|
|
102426
|
-
\`\`\`bash
|
|
102427
|
-
# Capture terminal output
|
|
102428
|
-
tmux capture-pane -p -t ${sessionName}
|
|
102429
|
-
|
|
102430
|
-
# Or capture with history (last 1000 lines)
|
|
102431
|
-
tmux capture-pane -p -t ${sessionName} -S -1000
|
|
102432
|
-
\`\`\`
|
|
102433
|
-
|
|
102434
|
-
The Bash tool can execute these commands directly. Do NOT retry with interactive_bash.`;
|
|
102655
|
+
return buildBlockedTmuxCommandMessage(rawSubcommand, parts);
|
|
102435
102656
|
}
|
|
102436
102657
|
const proc = spawnWithWindowsHide([...resolveTmuxExecutable2(tmuxPath2), ...parts], {
|
|
102437
102658
|
stdout: "pipe",
|
|
@@ -102902,7 +103123,7 @@ async function formatFullSession(task, client2, options) {
|
|
|
102902
103123
|
}
|
|
102903
103124
|
|
|
102904
103125
|
// src/features/background-agent/error-classifier.ts
|
|
102905
|
-
function
|
|
103126
|
+
function isRecord18(value) {
|
|
102906
103127
|
return typeof value === "object" && value !== null;
|
|
102907
103128
|
}
|
|
102908
103129
|
function isAbortedSessionError(error) {
|
|
@@ -102928,7 +103149,7 @@ function getErrorText(error) {
|
|
|
102928
103149
|
return "";
|
|
102929
103150
|
}
|
|
102930
103151
|
function extractErrorName2(error) {
|
|
102931
|
-
if (
|
|
103152
|
+
if (isRecord18(error) && typeof error["name"] === "string")
|
|
102932
103153
|
return error["name"];
|
|
102933
103154
|
if (error instanceof Error)
|
|
102934
103155
|
return error.name;
|
|
@@ -102939,11 +103160,11 @@ function extractErrorMessage(error) {
|
|
|
102939
103160
|
return;
|
|
102940
103161
|
if (typeof error === "string")
|
|
102941
103162
|
return error;
|
|
102942
|
-
if (
|
|
103163
|
+
if (isRecord18(error)) {
|
|
102943
103164
|
const dataRaw = error["data"];
|
|
102944
103165
|
const candidates = [
|
|
102945
103166
|
dataRaw,
|
|
102946
|
-
|
|
103167
|
+
isRecord18(dataRaw) ? dataRaw["error"] : undefined,
|
|
102947
103168
|
error["error"],
|
|
102948
103169
|
error["cause"],
|
|
102949
103170
|
error
|
|
@@ -102951,7 +103172,7 @@ function extractErrorMessage(error) {
|
|
|
102951
103172
|
for (const candidate of candidates) {
|
|
102952
103173
|
if (typeof candidate === "string" && candidate.length > 0)
|
|
102953
103174
|
return candidate;
|
|
102954
|
-
if (
|
|
103175
|
+
if (isRecord18(candidate) && typeof candidate["message"] === "string" && candidate["message"].length > 0) {
|
|
102955
103176
|
return candidate["message"];
|
|
102956
103177
|
}
|
|
102957
103178
|
}
|
|
@@ -102966,10 +103187,10 @@ function extractErrorMessage(error) {
|
|
|
102966
103187
|
}
|
|
102967
103188
|
function getSessionErrorMessage(properties) {
|
|
102968
103189
|
const errorRaw = properties["error"];
|
|
102969
|
-
if (!
|
|
103190
|
+
if (!isRecord18(errorRaw))
|
|
102970
103191
|
return;
|
|
102971
103192
|
const dataRaw = errorRaw["data"];
|
|
102972
|
-
if (
|
|
103193
|
+
if (isRecord18(dataRaw)) {
|
|
102973
103194
|
const message2 = dataRaw["message"];
|
|
102974
103195
|
if (typeof message2 === "string")
|
|
102975
103196
|
return message2;
|
|
@@ -103745,11 +103966,12 @@ function mergeWithClaudeCodeAgents(serverAgents, directory) {
|
|
|
103745
103966
|
const toAgentInfoList = (record) => Object.entries(record).map(([name, config2]) => ({
|
|
103746
103967
|
name,
|
|
103747
103968
|
mode: config2.mode,
|
|
103969
|
+
hidden: config2.hidden,
|
|
103748
103970
|
model: config2.model
|
|
103749
103971
|
}));
|
|
103750
103972
|
const mergedAgentMap = new Map;
|
|
103751
103973
|
const addIfAbsent = (agent) => {
|
|
103752
|
-
const key = agent.name.toLowerCase();
|
|
103974
|
+
const key = stripAgentListSortPrefix(agent.name).trim().toLowerCase();
|
|
103753
103975
|
if (!mergedAgentMap.has(key)) {
|
|
103754
103976
|
mergedAgentMap.set(key, agent);
|
|
103755
103977
|
}
|
|
@@ -103782,10 +104004,10 @@ function findPrimaryAgentMatch(agents, requestedAgentName) {
|
|
|
103782
104004
|
return agents.find((agent) => agent.mode === "primary" && matchesRequestedAgent(agent, requestedAgentName));
|
|
103783
104005
|
}
|
|
103784
104006
|
function findCallableAgentMatch(agents, requestedAgentName) {
|
|
103785
|
-
return agents.find((agent) => isTaskCallableAgentMode(agent.mode) && matchesRequestedAgent(agent, requestedAgentName));
|
|
104007
|
+
return agents.find((agent) => isTaskCallableAgentMode(agent.mode) && agent.hidden !== true && matchesRequestedAgent(agent, requestedAgentName));
|
|
103786
104008
|
}
|
|
103787
104009
|
function listCallableAgentNames(agents) {
|
|
103788
|
-
return agents.filter((agent) => isTaskCallableAgentMode(agent.mode)).map((agent) => stripAgentListSortPrefix(agent.name)).sort().join(", ");
|
|
104010
|
+
return agents.filter((agent) => isTaskCallableAgentMode(agent.mode) && agent.hidden !== true).map((agent) => stripAgentListSortPrefix(agent.name)).sort().join(", ");
|
|
103789
104011
|
}
|
|
103790
104012
|
|
|
103791
104013
|
// src/tools/call-omo-agent/background-executor.ts
|
|
@@ -105345,7 +105567,7 @@ init_logger();
|
|
|
105345
105567
|
init_shared();
|
|
105346
105568
|
var NON_TERMINAL_FINISH_REASONS = new Set(["tool-calls", "unknown"]);
|
|
105347
105569
|
var PENDING_TOOL_PART_TYPES = new Set(["tool", "tool_use", "tool-call"]);
|
|
105348
|
-
var
|
|
105570
|
+
var ACTIVE_SESSION_STATUSES2 = new Set(["busy", "retry", "running"]);
|
|
105349
105571
|
function wait(milliseconds) {
|
|
105350
105572
|
const sharedBuffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
|
|
105351
105573
|
const typedArray = new Int32Array(sharedBuffer);
|
|
@@ -105363,7 +105585,7 @@ function abortSyncSession(client2, sessionID, reason) {
|
|
|
105363
105585
|
});
|
|
105364
105586
|
}
|
|
105365
105587
|
function isActiveSessionStatus(status) {
|
|
105366
|
-
return status !== undefined &&
|
|
105588
|
+
return status !== undefined && ACTIVE_SESSION_STATUSES2.has(status.type);
|
|
105367
105589
|
}
|
|
105368
105590
|
async function fetchSessionMessages(client2, sessionID) {
|
|
105369
105591
|
const messagesResult = await client2.session.messages({ path: { id: sessionID } });
|
|
@@ -111697,10 +111919,10 @@ async function verifySessionExists(client2, sessionID, directory) {
|
|
|
111697
111919
|
|
|
111698
111920
|
// src/features/background-agent/session-status-classifier.ts
|
|
111699
111921
|
init_shared();
|
|
111700
|
-
var
|
|
111922
|
+
var ACTIVE_SESSION_STATUSES3 = new Set(["busy", "retry", "running"]);
|
|
111701
111923
|
var KNOWN_TERMINAL_STATUSES = new Set(["idle", "interrupted"]);
|
|
111702
111924
|
function isActiveSessionStatus2(type2) {
|
|
111703
|
-
if (
|
|
111925
|
+
if (ACTIVE_SESSION_STATUSES3.has(type2)) {
|
|
111704
111926
|
return true;
|
|
111705
111927
|
}
|
|
111706
111928
|
if (!KNOWN_TERMINAL_STATUSES.has(type2)) {
|
|
@@ -112000,6 +112222,7 @@ function createSubagentDepthLimitError(input) {
|
|
|
112000
112222
|
}
|
|
112001
112223
|
|
|
112002
112224
|
// src/features/background-agent/manager.ts
|
|
112225
|
+
var PENDING_PARENT_WAKE_RETRY_MS = 1000;
|
|
112003
112226
|
function resolveMessagePartInfo(properties) {
|
|
112004
112227
|
if (!properties || typeof properties !== "object") {
|
|
112005
112228
|
return;
|
|
@@ -112062,6 +112285,8 @@ class BackgroundManager {
|
|
|
112062
112285
|
completedTaskSummaries = new Map;
|
|
112063
112286
|
idleDeferralTimers = new Map;
|
|
112064
112287
|
notificationQueueByParent = new Map;
|
|
112288
|
+
pendingParentWakes = new Map;
|
|
112289
|
+
pendingParentWakeTimers = new Map;
|
|
112065
112290
|
observedOutputSessions = new Set;
|
|
112066
112291
|
observedIncompleteTodosBySession = new Map;
|
|
112067
112292
|
rootDescendantCounts;
|
|
@@ -113031,6 +113256,12 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
113031
113256
|
if (event.type === "session.idle") {
|
|
113032
113257
|
if (!props || typeof props !== "object")
|
|
113033
113258
|
return;
|
|
113259
|
+
const sessionID = resolveSessionEventID(props);
|
|
113260
|
+
if (sessionID) {
|
|
113261
|
+
this.enqueueNotificationForParent(sessionID, () => this.flushPendingParentWake(sessionID)).catch((error) => {
|
|
113262
|
+
log("[background-agent] Failed to flush pending parent wake:", { sessionID, error });
|
|
113263
|
+
});
|
|
113264
|
+
}
|
|
113034
113265
|
handleSessionIdleBackgroundEvent({
|
|
113035
113266
|
properties: props,
|
|
113036
113267
|
findBySession: (id) => {
|
|
@@ -113041,7 +113272,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
113041
113272
|
validateSessionHasOutput: (id) => this.validateSessionHasOutput(id),
|
|
113042
113273
|
checkSessionTodos: (id) => this.checkSessionTodos(id),
|
|
113043
113274
|
tryCompleteTask: (task, source) => this.tryCompleteTask(task, source),
|
|
113044
|
-
emitIdleEvent: (
|
|
113275
|
+
emitIdleEvent: (sessionID2) => this.handleEvent({ type: "session.idle", properties: { sessionID: sessionID2 } })
|
|
113045
113276
|
});
|
|
113046
113277
|
}
|
|
113047
113278
|
if (event.type === "session.error") {
|
|
@@ -113610,7 +113841,7 @@ ${originalText}`;
|
|
|
113610
113841
|
}, this.directory);
|
|
113611
113842
|
const messages = normalizeSDKResponse(messagesResp, []);
|
|
113612
113843
|
promptContext = resolvePromptContextFromSessionMessages(messages, task.parentSessionId);
|
|
113613
|
-
const normalizedTools =
|
|
113844
|
+
const normalizedTools = isRecord18(promptContext?.tools) ? normalizePromptTools(promptContext.tools) : undefined;
|
|
113614
113845
|
if (promptContext?.agent || promptContext?.model || normalizedTools) {
|
|
113615
113846
|
agent = promptContext?.agent ?? task.parentAgent;
|
|
113616
113847
|
model = promptContext?.model?.providerID && promptContext.model.modelID ? { providerID: promptContext.model.providerID, modelID: promptContext.model.modelID } : undefined;
|
|
@@ -113644,30 +113875,41 @@ ${originalText}`;
|
|
|
113644
113875
|
...variant !== undefined ? { variant } : {},
|
|
113645
113876
|
...resolvedTools ? { tools: resolvedTools } : {}
|
|
113646
113877
|
};
|
|
113647
|
-
|
|
113648
|
-
|
|
113649
|
-
|
|
113650
|
-
|
|
113651
|
-
noReply: !shouldReply,
|
|
113652
|
-
...parentPromptContext,
|
|
113653
|
-
parts: [createInternalAgentTextPart(notification2)]
|
|
113654
|
-
}
|
|
113655
|
-
}, this.directory);
|
|
113656
|
-
log("[background-agent] Sent notification to parent session:", {
|
|
113878
|
+
const shouldDeferNotification = await this.isSessionActive(task.parentSessionId);
|
|
113879
|
+
if (shouldDeferNotification) {
|
|
113880
|
+
this.queuePendingParentWake(task.parentSessionId, notification2, parentPromptContext, shouldReply);
|
|
113881
|
+
log("[background-agent] Deferred notification until parent session is idle:", {
|
|
113657
113882
|
taskId: task.id,
|
|
113658
113883
|
allComplete,
|
|
113659
113884
|
isTaskFailure,
|
|
113660
|
-
|
|
113885
|
+
shouldReply
|
|
113661
113886
|
});
|
|
113662
|
-
}
|
|
113663
|
-
|
|
113664
|
-
|
|
113887
|
+
} else {
|
|
113888
|
+
try {
|
|
113889
|
+
await promptAsyncInDirectory(this.client, {
|
|
113890
|
+
path: { id: task.parentSessionId },
|
|
113891
|
+
body: {
|
|
113892
|
+
noReply: !shouldReply,
|
|
113893
|
+
...parentPromptContext,
|
|
113894
|
+
parts: [createInternalAgentTextPart(notification2)]
|
|
113895
|
+
}
|
|
113896
|
+
}, this.directory);
|
|
113897
|
+
log("[background-agent] Sent notification to parent session:", {
|
|
113665
113898
|
taskId: task.id,
|
|
113666
|
-
|
|
113899
|
+
allComplete,
|
|
113900
|
+
isTaskFailure,
|
|
113901
|
+
noReply: !shouldReply
|
|
113667
113902
|
});
|
|
113668
|
-
|
|
113669
|
-
|
|
113670
|
-
|
|
113903
|
+
} catch (error) {
|
|
113904
|
+
if (isAbortedSessionError(error)) {
|
|
113905
|
+
log("[background-agent] Parent session aborted while sending notification; continuing cleanup:", {
|
|
113906
|
+
taskId: task.id,
|
|
113907
|
+
parentSessionID: task.parentSessionId
|
|
113908
|
+
});
|
|
113909
|
+
this.queuePendingNotification(task.parentSessionId, notification2);
|
|
113910
|
+
} else {
|
|
113911
|
+
log("[background-agent] Failed to send notification:", error);
|
|
113912
|
+
}
|
|
113671
113913
|
}
|
|
113672
113914
|
}
|
|
113673
113915
|
} else {
|
|
@@ -113680,6 +113922,80 @@ ${originalText}`;
|
|
|
113680
113922
|
this.scheduleTaskRemoval(task.id);
|
|
113681
113923
|
}
|
|
113682
113924
|
}
|
|
113925
|
+
async isSessionActive(sessionID) {
|
|
113926
|
+
return isSessionActive(this.client, sessionID);
|
|
113927
|
+
}
|
|
113928
|
+
queuePendingParentWake(sessionID, notification2, promptContext, shouldReply) {
|
|
113929
|
+
const pendingWake = this.pendingParentWakes.get(sessionID);
|
|
113930
|
+
if (pendingWake) {
|
|
113931
|
+
pendingWake.notifications.push(notification2);
|
|
113932
|
+
pendingWake.promptContext = promptContext;
|
|
113933
|
+
pendingWake.shouldReply = pendingWake.shouldReply || shouldReply;
|
|
113934
|
+
} else {
|
|
113935
|
+
this.pendingParentWakes.set(sessionID, {
|
|
113936
|
+
promptContext,
|
|
113937
|
+
notifications: [notification2],
|
|
113938
|
+
shouldReply
|
|
113939
|
+
});
|
|
113940
|
+
}
|
|
113941
|
+
this.schedulePendingParentWakeFlush(sessionID);
|
|
113942
|
+
}
|
|
113943
|
+
async flushPendingParentWake(sessionID) {
|
|
113944
|
+
const pendingWake = this.pendingParentWakes.get(sessionID);
|
|
113945
|
+
if (!pendingWake) {
|
|
113946
|
+
this.clearPendingParentWakeTimer(sessionID);
|
|
113947
|
+
return;
|
|
113948
|
+
}
|
|
113949
|
+
if (await this.isSessionActive(sessionID)) {
|
|
113950
|
+
this.schedulePendingParentWakeFlush(sessionID);
|
|
113951
|
+
return;
|
|
113952
|
+
}
|
|
113953
|
+
this.pendingParentWakes.delete(sessionID);
|
|
113954
|
+
this.clearPendingParentWakeTimer(sessionID);
|
|
113955
|
+
await settleAfterSessionIdle();
|
|
113956
|
+
if (await this.isSessionActive(sessionID)) {
|
|
113957
|
+
this.pendingParentWakes.set(sessionID, pendingWake);
|
|
113958
|
+
this.schedulePendingParentWakeFlush(sessionID);
|
|
113959
|
+
return;
|
|
113960
|
+
}
|
|
113961
|
+
const notificationContent = pendingWake.notifications.join(`
|
|
113962
|
+
|
|
113963
|
+
`);
|
|
113964
|
+
try {
|
|
113965
|
+
await promptAsyncInDirectory(this.client, {
|
|
113966
|
+
path: { id: sessionID },
|
|
113967
|
+
body: {
|
|
113968
|
+
noReply: !pendingWake.shouldReply,
|
|
113969
|
+
...pendingWake.promptContext,
|
|
113970
|
+
parts: [createInternalAgentTextPart(notificationContent)]
|
|
113971
|
+
}
|
|
113972
|
+
}, this.directory);
|
|
113973
|
+
log("[background-agent] Sent deferred parent wake:", { sessionID });
|
|
113974
|
+
} catch (error) {
|
|
113975
|
+
this.queuePendingNotification(sessionID, notificationContent);
|
|
113976
|
+
log("[background-agent] Failed to send deferred parent wake:", { sessionID, error });
|
|
113977
|
+
}
|
|
113978
|
+
}
|
|
113979
|
+
schedulePendingParentWakeFlush(sessionID) {
|
|
113980
|
+
if (this.pendingParentWakeTimers.has(sessionID)) {
|
|
113981
|
+
return;
|
|
113982
|
+
}
|
|
113983
|
+
const timer = setTimeout(() => {
|
|
113984
|
+
this.pendingParentWakeTimers.delete(sessionID);
|
|
113985
|
+
this.enqueueNotificationForParent(sessionID, () => this.flushPendingParentWake(sessionID)).catch((error) => {
|
|
113986
|
+
log("[background-agent] Failed to retry pending parent wake:", { sessionID, error });
|
|
113987
|
+
});
|
|
113988
|
+
}, PENDING_PARENT_WAKE_RETRY_MS);
|
|
113989
|
+
this.pendingParentWakeTimers.set(sessionID, timer);
|
|
113990
|
+
}
|
|
113991
|
+
clearPendingParentWakeTimer(sessionID) {
|
|
113992
|
+
const timer = this.pendingParentWakeTimers.get(sessionID);
|
|
113993
|
+
if (!timer) {
|
|
113994
|
+
return;
|
|
113995
|
+
}
|
|
113996
|
+
clearTimeout(timer);
|
|
113997
|
+
this.pendingParentWakeTimers.delete(sessionID);
|
|
113998
|
+
}
|
|
113683
113999
|
hasRunningTasks() {
|
|
113684
114000
|
for (const task of this.tasks.values()) {
|
|
113685
114001
|
if (task.status === "running")
|
|
@@ -113949,6 +114265,10 @@ ${originalText}`;
|
|
|
113949
114265
|
clearTimeout(timer);
|
|
113950
114266
|
}
|
|
113951
114267
|
this.idleDeferralTimers.clear();
|
|
114268
|
+
for (const timer of this.pendingParentWakeTimers.values()) {
|
|
114269
|
+
clearTimeout(timer);
|
|
114270
|
+
}
|
|
114271
|
+
this.pendingParentWakeTimers.clear();
|
|
113952
114272
|
for (const sessionID of trackedSessionIDs) {
|
|
113953
114273
|
subagentSessions.delete(sessionID);
|
|
113954
114274
|
SessionCategoryRegistry.remove(sessionID);
|
|
@@ -113959,6 +114279,7 @@ ${originalText}`;
|
|
|
113959
114279
|
this.notifications.clear();
|
|
113960
114280
|
this.pendingNotifications.clear();
|
|
113961
114281
|
this.pendingByParent.clear();
|
|
114282
|
+
this.pendingParentWakes.clear();
|
|
113962
114283
|
this.notificationQueueByParent.clear();
|
|
113963
114284
|
this.rootDescendantCounts.clear();
|
|
113964
114285
|
this.queuesByKey.clear();
|
|
@@ -114213,7 +114534,7 @@ async function getOrRegisterClient(options) {
|
|
|
114213
114534
|
}
|
|
114214
114535
|
}
|
|
114215
114536
|
function parseRegistrationResponse(data) {
|
|
114216
|
-
if (!
|
|
114537
|
+
if (!isRecord19(data))
|
|
114217
114538
|
return null;
|
|
114218
114539
|
const clientId = data.client_id;
|
|
114219
114540
|
if (typeof clientId !== "string" || clientId.length === 0)
|
|
@@ -114224,7 +114545,7 @@ function parseRegistrationResponse(data) {
|
|
|
114224
114545
|
}
|
|
114225
114546
|
return { clientId };
|
|
114226
114547
|
}
|
|
114227
|
-
function
|
|
114548
|
+
function isRecord19(value) {
|
|
114228
114549
|
return typeof value === "object" && value !== null;
|
|
114229
114550
|
}
|
|
114230
114551
|
|
|
@@ -137318,11 +137639,11 @@ async function createTools(args) {
|
|
|
137318
137639
|
// src/plugin/chat-params.ts
|
|
137319
137640
|
init_shared();
|
|
137320
137641
|
var SAFE_MAX_OUTPUT_TOKENS_FALLBACK = 4096;
|
|
137321
|
-
function
|
|
137642
|
+
function isRecord20(value) {
|
|
137322
137643
|
return typeof value === "object" && value !== null;
|
|
137323
137644
|
}
|
|
137324
137645
|
function buildChatParamsInput(raw) {
|
|
137325
|
-
if (!
|
|
137646
|
+
if (!isRecord20(raw))
|
|
137326
137647
|
return null;
|
|
137327
137648
|
const sessionID = raw.sessionID;
|
|
137328
137649
|
const agent = raw.agent;
|
|
@@ -137331,16 +137652,16 @@ function buildChatParamsInput(raw) {
|
|
|
137331
137652
|
const message = raw.message;
|
|
137332
137653
|
if (typeof sessionID !== "string")
|
|
137333
137654
|
return null;
|
|
137334
|
-
if (!
|
|
137655
|
+
if (!isRecord20(model))
|
|
137335
137656
|
return null;
|
|
137336
|
-
if (!
|
|
137657
|
+
if (!isRecord20(provider))
|
|
137337
137658
|
return null;
|
|
137338
|
-
if (!
|
|
137659
|
+
if (!isRecord20(message))
|
|
137339
137660
|
return null;
|
|
137340
137661
|
let agentName;
|
|
137341
137662
|
if (typeof agent === "string") {
|
|
137342
137663
|
agentName = agent;
|
|
137343
|
-
} else if (
|
|
137664
|
+
} else if (isRecord20(agent)) {
|
|
137344
137665
|
const name = agent.name;
|
|
137345
137666
|
if (typeof name === "string") {
|
|
137346
137667
|
agentName = name;
|
|
@@ -137367,12 +137688,12 @@ function buildChatParamsInput(raw) {
|
|
|
137367
137688
|
};
|
|
137368
137689
|
}
|
|
137369
137690
|
function isChatParamsOutput(raw) {
|
|
137370
|
-
if (!
|
|
137691
|
+
if (!isRecord20(raw))
|
|
137371
137692
|
return false;
|
|
137372
|
-
if (!
|
|
137693
|
+
if (!isRecord20(raw.options)) {
|
|
137373
137694
|
raw.options = {};
|
|
137374
137695
|
}
|
|
137375
|
-
return
|
|
137696
|
+
return isRecord20(raw.options);
|
|
137376
137697
|
}
|
|
137377
137698
|
function createChatParamsHandler(args) {
|
|
137378
137699
|
return async (input, output) => {
|
|
@@ -137412,7 +137733,7 @@ function createChatParamsHandler(args) {
|
|
|
137412
137733
|
temperature: typeof output.temperature === "number" ? output.temperature : undefined,
|
|
137413
137734
|
topP: typeof output.topP === "number" ? output.topP : undefined,
|
|
137414
137735
|
maxTokens: typeof output.maxOutputTokens === "number" ? output.maxOutputTokens : undefined,
|
|
137415
|
-
thinking:
|
|
137736
|
+
thinking: isRecord20(output.options.thinking) ? output.options.thinking : undefined
|
|
137416
137737
|
},
|
|
137417
137738
|
capabilities
|
|
137418
137739
|
});
|
|
@@ -137469,20 +137790,20 @@ function createChatParamsHandler(args) {
|
|
|
137469
137790
|
init_shared();
|
|
137470
137791
|
var INTERNAL_MARKER_CACHE_LIMIT = 1000;
|
|
137471
137792
|
var internalMarkerCache = new Map;
|
|
137472
|
-
function
|
|
137793
|
+
function isRecord21(value) {
|
|
137473
137794
|
return typeof value === "object" && value !== null;
|
|
137474
137795
|
}
|
|
137475
137796
|
function buildChatHeadersInput(raw) {
|
|
137476
|
-
if (!
|
|
137797
|
+
if (!isRecord21(raw))
|
|
137477
137798
|
return null;
|
|
137478
137799
|
const sessionID = raw.sessionID;
|
|
137479
137800
|
const provider = raw.provider;
|
|
137480
137801
|
const message = raw.message;
|
|
137481
137802
|
if (typeof sessionID !== "string")
|
|
137482
137803
|
return null;
|
|
137483
|
-
if (!
|
|
137804
|
+
if (!isRecord21(provider) || typeof provider.id !== "string")
|
|
137484
137805
|
return null;
|
|
137485
|
-
if (!
|
|
137806
|
+
if (!isRecord21(message))
|
|
137486
137807
|
return null;
|
|
137487
137808
|
return {
|
|
137488
137809
|
sessionID,
|
|
@@ -137494,12 +137815,12 @@ function buildChatHeadersInput(raw) {
|
|
|
137494
137815
|
};
|
|
137495
137816
|
}
|
|
137496
137817
|
function isChatHeadersOutput(raw) {
|
|
137497
|
-
if (!
|
|
137818
|
+
if (!isRecord21(raw))
|
|
137498
137819
|
return false;
|
|
137499
|
-
if (!
|
|
137820
|
+
if (!isRecord21(raw.headers)) {
|
|
137500
137821
|
raw.headers = {};
|
|
137501
137822
|
}
|
|
137502
|
-
return
|
|
137823
|
+
return isRecord21(raw.headers);
|
|
137503
137824
|
}
|
|
137504
137825
|
function isCopilotProvider(providerID) {
|
|
137505
137826
|
return providerID === "github-copilot" || providerID === "github-copilot-enterprise";
|
|
@@ -137515,7 +137836,7 @@ async function hasInternalMarker(client2, sessionID, messageID) {
|
|
|
137515
137836
|
path: { id: sessionID, messageID }
|
|
137516
137837
|
});
|
|
137517
137838
|
const data = response.data;
|
|
137518
|
-
if (!
|
|
137839
|
+
if (!isRecord21(data) || !Array.isArray(data.parts)) {
|
|
137519
137840
|
internalMarkerCache.set(cacheKey, false);
|
|
137520
137841
|
if (internalMarkerCache.size > INTERNAL_MARKER_CACHE_LIMIT) {
|
|
137521
137842
|
internalMarkerCache.clear();
|
|
@@ -137523,7 +137844,7 @@ async function hasInternalMarker(client2, sessionID, messageID) {
|
|
|
137523
137844
|
return false;
|
|
137524
137845
|
}
|
|
137525
137846
|
const hasMarker = data.parts.some((part) => {
|
|
137526
|
-
if (!
|
|
137847
|
+
if (!isRecord21(part) || part.type !== "text" || typeof part.text !== "string") {
|
|
137527
137848
|
return false;
|
|
137528
137849
|
}
|
|
137529
137850
|
return part.text.includes(OMO_INTERNAL_INITIATOR_MARKER);
|
|
@@ -137560,8 +137881,8 @@ function createChatHeadersHandler(args) {
|
|
|
137560
137881
|
return;
|
|
137561
137882
|
if (!isCopilotProvider(normalizedInput.provider.id))
|
|
137562
137883
|
return;
|
|
137563
|
-
const model =
|
|
137564
|
-
const api = model &&
|
|
137884
|
+
const model = isRecord21(input) && isRecord21(input.model) ? input.model : undefined;
|
|
137885
|
+
const api = model && isRecord21(model.api) ? model.api : undefined;
|
|
137565
137886
|
if (api?.npm === "@ai-sdk/github-copilot")
|
|
137566
137887
|
return;
|
|
137567
137888
|
if (!await isOmoInternalMessage(normalizedInput, ctx.client))
|
|
@@ -138258,7 +138579,16 @@ function createTeamIdleWakeHint(ctx, config2, options) {
|
|
|
138258
138579
|
return;
|
|
138259
138580
|
}
|
|
138260
138581
|
applyMemberSessionRouting(sessionID, memberEntry);
|
|
138261
|
-
await
|
|
138582
|
+
if (!await shouldPromptAfterSessionIdle(ctx.client, sessionID, options?.idleSettleMs)) {
|
|
138583
|
+
log("team idle wake hint skipped because session is active", {
|
|
138584
|
+
event: "team-mode-idle-wake-hint-active-session",
|
|
138585
|
+
teamRunId: runtimeState.teamRunId,
|
|
138586
|
+
memberName: memberEntry.name,
|
|
138587
|
+
sessionID,
|
|
138588
|
+
unreadCount: unreadMessages.length
|
|
138589
|
+
});
|
|
138590
|
+
return;
|
|
138591
|
+
}
|
|
138262
138592
|
await ctx.client.session.promptAsync({
|
|
138263
138593
|
path: { id: sessionID },
|
|
138264
138594
|
body: buildMemberPromptBody(memberEntry, buildWakeHint(unreadMessages.length)),
|
|
@@ -138529,14 +138859,14 @@ function normalizeSessionStatusToIdle(input) {
|
|
|
138529
138859
|
|
|
138530
138860
|
// src/plugin/event.ts
|
|
138531
138861
|
init_event_session_id();
|
|
138532
|
-
function
|
|
138862
|
+
function isRecord22(value) {
|
|
138533
138863
|
return typeof value === "object" && value !== null;
|
|
138534
138864
|
}
|
|
138535
138865
|
function normalizeFallbackModelID(modelID) {
|
|
138536
138866
|
return modelID.replace(/-thinking$/i, "").replace(/-max$/i, "").replace(/-high$/i, "");
|
|
138537
138867
|
}
|
|
138538
138868
|
function extractErrorName3(error) {
|
|
138539
|
-
if (
|
|
138869
|
+
if (isRecord22(error) && typeof error.name === "string")
|
|
138540
138870
|
return error.name;
|
|
138541
138871
|
if (error instanceof Error)
|
|
138542
138872
|
return error.name;
|
|
@@ -138547,16 +138877,16 @@ function extractErrorMessage3(error) {
|
|
|
138547
138877
|
return "";
|
|
138548
138878
|
if (typeof error === "string")
|
|
138549
138879
|
return error;
|
|
138550
|
-
if (
|
|
138880
|
+
if (isRecord22(error)) {
|
|
138551
138881
|
const candidates = [
|
|
138552
138882
|
error.data,
|
|
138553
|
-
|
|
138883
|
+
isRecord22(error.data) ? error.data.error : undefined,
|
|
138554
138884
|
error.error,
|
|
138555
138885
|
error.cause,
|
|
138556
138886
|
error
|
|
138557
138887
|
];
|
|
138558
138888
|
for (const candidate of candidates) {
|
|
138559
|
-
if (
|
|
138889
|
+
if (isRecord22(candidate) && typeof candidate.message === "string" && candidate.message.length > 0) {
|
|
138560
138890
|
return candidate.message;
|
|
138561
138891
|
}
|
|
138562
138892
|
}
|
|
@@ -138612,6 +138942,10 @@ function createEventHandler2(args) {
|
|
|
138612
138942
|
const lastHandledRetryStatusKey = new Map;
|
|
138613
138943
|
const lastKnownModelBySession = new Map;
|
|
138614
138944
|
const resolveFallbackProviderID = (sessionID, providerHint) => {
|
|
138945
|
+
const normalizedProviderHint = providerHint?.trim();
|
|
138946
|
+
if (normalizedProviderHint) {
|
|
138947
|
+
return normalizedProviderHint;
|
|
138948
|
+
}
|
|
138615
138949
|
const sessionModel = getSessionModel(sessionID);
|
|
138616
138950
|
if (sessionModel?.providerID) {
|
|
138617
138951
|
return sessionModel.providerID;
|
|
@@ -138620,10 +138954,6 @@ function createEventHandler2(args) {
|
|
|
138620
138954
|
if (lastKnownModel?.providerID) {
|
|
138621
138955
|
return lastKnownModel.providerID;
|
|
138622
138956
|
}
|
|
138623
|
-
const normalizedProviderHint = providerHint?.trim();
|
|
138624
|
-
if (normalizedProviderHint) {
|
|
138625
|
-
return normalizedProviderHint;
|
|
138626
|
-
}
|
|
138627
138957
|
const connectedProvider = readConnectedProvidersCache()?.[0];
|
|
138628
138958
|
if (connectedProvider) {
|
|
138629
138959
|
return connectedProvider;
|
|
@@ -138638,7 +138968,7 @@ function createEventHandler2(args) {
|
|
|
138638
138968
|
if (input.event.type.startsWith("message.") || input.event.type.startsWith("tool.")) {
|
|
138639
138969
|
return resolveMessageEventSessionID(properties);
|
|
138640
138970
|
}
|
|
138641
|
-
const record3 =
|
|
138971
|
+
const record3 = isRecord22(properties) ? properties : undefined;
|
|
138642
138972
|
const sessionID = record3?.sessionID;
|
|
138643
138973
|
return typeof sessionID === "string" && sessionID.length > 0 ? sessionID : undefined;
|
|
138644
138974
|
};
|
|
@@ -138737,7 +139067,7 @@ function createEventHandler2(args) {
|
|
|
138737
139067
|
...launchAgent ? { agent: launchAgent } : {},
|
|
138738
139068
|
...launchModel ? { model: launchModel } : {},
|
|
138739
139069
|
...launchVariant ? { variant: launchVariant } : {},
|
|
138740
|
-
parts: [
|
|
139070
|
+
parts: [createInternalAgentContinuationTextPart("continue")]
|
|
138741
139071
|
},
|
|
138742
139072
|
query: { directory: pluginContext.directory }
|
|
138743
139073
|
};
|
|
@@ -139044,7 +139374,7 @@ function createEventHandler2(args) {
|
|
|
139044
139374
|
});
|
|
139045
139375
|
await pluginContext.client.session.prompt({
|
|
139046
139376
|
path: { id: sessionID },
|
|
139047
|
-
body: { parts: [
|
|
139377
|
+
body: { parts: [createInternalAgentContinuationTextPart("continue")] },
|
|
139048
139378
|
query: { directory: pluginContext.directory }
|
|
139049
139379
|
}).catch(() => {});
|
|
139050
139380
|
}
|